]> granicus.if.org Git - php/commitdiff
Fix variance checks on resolved union types
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 3 Nov 2020 13:15:05 +0000 (14:15 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 3 Nov 2020 13:19:15 +0000 (14:19 +0100)
This is a bit annoying: When preloading is used, types might be
resolved during inheritance checks, so we need to deal with CE
types rather than just NAME types everywhere.

Zend/zend_inheritance.c
ext/opcache/tests/preload_variance.inc

index 191126eed79f08d93895c1339afb3e28e8ce0d77..34489938a92cb55cc5e5cda7a9b5b454efb42119 100644 (file)
@@ -364,11 +364,10 @@ typedef enum {
 } inheritance_status;
 
 static inheritance_status zend_perform_covariant_class_type_check(
-               zend_class_entry *fe_scope, zend_string *fe_class_name,
+               zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce,
                zend_class_entry *proto_scope, zend_type proto_type,
                zend_bool register_unresolved) {
        zend_bool have_unresolved = 0;
-       zend_class_entry *fe_ce = NULL;
        if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) {
                /* Currently, any class name would be allowed here. We still perform a class lookup
                 * for forward-compatibility reasons, as we may have named types in the future that
@@ -391,6 +390,7 @@ static inheritance_status zend_perform_covariant_class_type_check(
 
        zend_type *single_type;
        ZEND_TYPE_FOREACH(proto_type, single_type) {
+               zend_class_entry *proto_ce;
                if (ZEND_TYPE_HAS_NAME(*single_type)) {
                        zend_string *proto_class_name =
                                resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
@@ -398,16 +398,20 @@ static inheritance_status zend_perform_covariant_class_type_check(
                                return INHERITANCE_SUCCESS;
                        }
 
-                       /* Make sure to always load both classes, to avoid only registering one of them as
-                        * a delayed autoload. */
                        if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
-                       zend_class_entry *proto_ce =
+                       proto_ce =
                                lookup_class(proto_scope, proto_class_name, register_unresolved);
-                       if (!fe_ce || !proto_ce) {
-                               have_unresolved = 1;
-                       } else if (unlinked_instanceof(fe_ce, proto_ce)) {
-                               return INHERITANCE_SUCCESS;
-                       }
+               } else if (ZEND_TYPE_HAS_CE(*single_type)) {
+                       if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
+                       proto_ce = ZEND_TYPE_CE(*single_type);
+               } else {
+                       continue;
+               }
+
+               if (!fe_ce || !proto_ce) {
+                       have_unresolved = 1;
+               } else if (unlinked_instanceof(fe_ce, proto_ce)) {
+                       return INHERITANCE_SUCCESS;
                }
        } ZEND_TYPE_FOREACH_END();
 
@@ -448,56 +452,56 @@ static inheritance_status zend_perform_covariant_type_check(
                }
        }
 
-       if (ZEND_TYPE_HAS_NAME(fe_type)) {
-               zend_string *fe_class_name = resolve_class_name(fe_scope, ZEND_TYPE_NAME(fe_type));
-               inheritance_status status = zend_perform_covariant_class_type_check(
-                       fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 0);
-               if (status != INHERITANCE_UNRESOLVED) {
-                       return status;
-               }
-
-               zend_perform_covariant_class_type_check(
-                       fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 1);
-               return INHERITANCE_UNRESOLVED;
-       }
-
-       if (ZEND_TYPE_HAS_LIST(fe_type)) {
-               zend_type *list_type;
-               zend_bool all_success = 1;
+       zend_type *single_type;
+       zend_bool all_success = 1;
 
-               /* First try to check whether we can succeed without resolving anything */
-               ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) {
-                       ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
+       /* First try to check whether we can succeed without resolving anything */
+       ZEND_TYPE_FOREACH(fe_type, single_type) {
+               inheritance_status status;
+               if (ZEND_TYPE_HAS_NAME(*single_type)) {
                        zend_string *fe_class_name =
-                               resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type));
-                       inheritance_status status = zend_perform_covariant_class_type_check(
-                               fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 0);
-                       if (status == INHERITANCE_ERROR) {
-                               return INHERITANCE_ERROR;
-                       }
-
-                       if (status != INHERITANCE_SUCCESS) {
-                               all_success = 0;
-                       }
-               } ZEND_TYPE_LIST_FOREACH_END();
+                               resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
+                       status = zend_perform_covariant_class_type_check(
+                               fe_scope, fe_class_name, NULL,
+                               proto_scope, proto_type, /* register_unresolved */ 0);
+               } else if (ZEND_TYPE_HAS_CE(*single_type)) {
+                       zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type);
+                       status = zend_perform_covariant_class_type_check(
+                               fe_scope, fe_ce->name, fe_ce,
+                               proto_scope, proto_type, /* register_unresolved */ 0);
+               } else {
+                       continue;
+               }
 
-               /* All individual checks succeeded, overall success */
-               if (all_success) {
-                       return INHERITANCE_SUCCESS;
+               if (status == INHERITANCE_ERROR) {
+                       return INHERITANCE_ERROR;
                }
+               if (status != INHERITANCE_SUCCESS) {
+                       all_success = 0;
+               }
+       } ZEND_TYPE_FOREACH_END();
 
-               /* Register all classes that may have to be resolved */
-               ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(fe_type), list_type) {
-                       ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
-                       zend_string *fe_class_name =
-                               resolve_class_name(fe_scope, ZEND_TYPE_NAME(*list_type));
-                       zend_perform_covariant_class_type_check(
-                               fe_scope, fe_class_name, proto_scope, proto_type, /* register_unresolved */ 1);
-               } ZEND_TYPE_LIST_FOREACH_END();
-               return INHERITANCE_UNRESOLVED;
+       /* All individual checks succeeded, overall success */
+       if (all_success) {
+               return INHERITANCE_SUCCESS;
        }
 
-       return INHERITANCE_SUCCESS;
+       /* Register all classes that may have to be resolved */
+       ZEND_TYPE_FOREACH(fe_type, single_type) {
+               if (ZEND_TYPE_HAS_NAME(*single_type)) {
+                       zend_string *fe_class_name =
+                               resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
+                       zend_perform_covariant_class_type_check(
+                               fe_scope, fe_class_name, NULL,
+                               proto_scope, proto_type, /* register_unresolved */ 1);
+               } else if (ZEND_TYPE_HAS_CE(*single_type)) {
+                       zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type);
+                       zend_perform_covariant_class_type_check(
+                               fe_scope, fe_ce->name, fe_ce,
+                               proto_scope, proto_type, /* register_unresolved */ 1);
+               }
+       } ZEND_TYPE_FOREACH_END();
+       return INHERITANCE_UNRESOLVED;
 }
 /* }}} */
 
index b1e84b5b5d92cd320d699e1e2536fc6209ddc990..eae3cd7152614e463e43657a54a2a20553059aa5 100644 (file)
@@ -25,9 +25,11 @@ class D extends C {
 interface I {}
 interface J extends I {}
 class E {
+    public I|J $prop;
     public function method($a): I {}
 }
 class F extends E {
+    public J|I $prop;
     public function method($a): J {}
 }