summaryrefslogtreecommitdiff
path: root/Zend/zend_inheritance.c
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-01-07 15:06:36 +0100
committerNikita Popov <nikita.ppv@gmail.com>2020-02-17 11:51:09 +0100
commit43443857b74503246ee4ca25859b302ed0ebc078 (patch)
treec343eb388a2c3327d8d6d6895c63a8051cb44db9 /Zend/zend_inheritance.c
parentd2ba8485721144dbb235d183a82e34d8bb1720eb (diff)
downloadphp-git-43443857b74503246ee4ca25859b302ed0ebc078.tar.gz
Add static return type
RFC: https://wiki.php.net/rfc/static_return_type The "static" type is represented as MAY_BE_STATIC, rather than a class type like "self" and "parent", as it has special resolution semantics, and cannot be cached in the runtime cache. Closes GH-5062.
Diffstat (limited to 'Zend/zend_inheritance.c')
-rw-r--r--Zend/zend_inheritance.c37
1 files changed, 34 insertions, 3 deletions
diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c
index 5abe1c55d4..219c1ffcc9 100644
--- a/Zend/zend_inheritance.c
+++ b/Zend/zend_inheritance.c
@@ -333,6 +333,28 @@ static zend_bool zend_type_contains_traversable(zend_type type) {
return 0;
}
+static zend_bool zend_type_permits_self(
+ zend_type type, zend_class_entry *scope, zend_class_entry *self) {
+ if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
+ return 1;
+ }
+
+ /* Any types that may satisfy self must have already been loaded at this point
+ * (as a parent or interface), so we never need to register delayed variance obligations
+ * for this case. */
+ zend_type *single_type;
+ ZEND_TYPE_FOREACH(type, single_type) {
+ if (ZEND_TYPE_HAS_NAME(*single_type)) {
+ zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
+ zend_class_entry *ce = lookup_class(self, name, /* register_unresolved */ 0);
+ if (ce && unlinked_instanceof(self, ce)) {
+ return 1;
+ }
+ }
+ } ZEND_TYPE_FOREACH_END();
+ return 0;
+}
+
/* Unresolved means that class declarations that are currently not available are needed to
* determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
* as an ERROR. */
@@ -406,13 +428,22 @@ static inheritance_status zend_perform_covariant_type_check(
if (added_types) {
// TODO: Make "iterable" an alias of "array|Traversable" instead,
// so these special cases will be handled automatically.
- if (added_types == MAY_BE_ITERABLE
+ if ((added_types & MAY_BE_ITERABLE)
&& (proto_type_mask & MAY_BE_ARRAY)
&& zend_type_contains_traversable(proto_type)) {
/* Replacing array|Traversable with iterable is okay */
- } else if (added_types == MAY_BE_ARRAY && (proto_type_mask & MAY_BE_ITERABLE)) {
+ added_types &= ~MAY_BE_ITERABLE;
+ }
+ if ((added_types & MAY_BE_ARRAY) && (proto_type_mask & MAY_BE_ITERABLE)) {
/* Replacing iterable with array is okay */
- } else {
+ added_types &= ~MAY_BE_ARRAY;
+ }
+ if ((added_types & MAY_BE_STATIC)
+ && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
+ /* Replacing type that accepts self with static is okay */
+ added_types &= ~MAY_BE_STATIC;
+ }
+ if (added_types) {
/* Otherwise adding new types is illegal */
return INHERITANCE_ERROR;
}