]> granicus.if.org Git - php/commitdiff
Merge branch 'PHP-7.4'
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 17 Oct 2019 11:42:47 +0000 (13:42 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 17 Oct 2019 11:42:47 +0000 (13:42 +0200)
* PHP-7.4:
  Integrate property types with variance system

1  2 
Zend/zend_inheritance.c

index 2ac73f617f2e0c9338be8407755f68da8dbedef5,cc85af6859cf2fe74cb2a349abc657e317019020..5f9389ed6ef99c49daf6d03e48a4316ded85a43a
  
  static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
  static void add_compatibility_obligation(
 -              zend_class_entry *ce, const zend_function *child_fn, const zend_function *parent_fn,
 -              zend_bool always_error);
 +              zend_class_entry *ce, const zend_function *child_fn, const zend_function *parent_fn);
+ static void add_property_compatibility_obligation(
+               zend_class_entry *ce, const zend_property_info *child_prop,
+               const zend_property_info *parent_prop);
  
  static void overridden_ptr_dtor(zval *zv) /* {{{ */
  {
@@@ -339,10 -342,11 +341,11 @@@ static inheritance_status zend_perform_
                }
  
                return unlinked_instanceof(fe_ce, proto_ce) ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
 -      } else if (ZEND_TYPE_CODE(proto_type) == IS_ITERABLE) {
 +      } else if (ZEND_TYPE_MASK(proto_type) & MAY_BE_ITERABLE) {
                if (ZEND_TYPE_IS_CLASS(fe_type)) {
-                       zend_string *fe_class_name = resolve_class_name(fe, ZEND_TYPE_NAME(fe_type));
-                       zend_class_entry *fe_ce = lookup_class(fe, fe_class_name);
+                       zend_string *fe_class_name =
+                               resolve_class_name(fe->common.scope, ZEND_TYPE_NAME(fe_type));
+                       zend_class_entry *fe_ce = lookup_class(fe->common.scope, fe_class_name);
                        if (!fe_ce) {
                                *unresolved_class = fe_class_name;
                                return INHERITANCE_UNRESOLVED;
@@@ -872,11 -912,27 +860,25 @@@ inheritance_status property_types_compa
        /* Check for class aliases */
        parent_type_ce = ZEND_TYPE_IS_CE(parent_info->type)
                ? ZEND_TYPE_CE(parent_info->type)
-               : zend_lookup_class(parent_name);
+               : lookup_class(parent_info->ce, parent_name);
        child_type_ce = ZEND_TYPE_IS_CE(child_info->type)
                ? ZEND_TYPE_CE(child_info->type)
-               : zend_lookup_class(child_name);
-       return parent_type_ce && child_type_ce && parent_type_ce == child_type_ce;
+               : lookup_class(child_info->ce, child_name);
+       if (!parent_type_ce || !child_type_ce) {
+               return INHERITANCE_UNRESOLVED;
+       }
+       return parent_type_ce == child_type_ce ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
+ }
+ static void emit_incompatible_property_error(
+               const zend_property_info *child, const zend_property_info *parent) {
++      zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
+       zend_error_noreturn(E_COMPILE_ERROR,
 -              "Type of %s::$%s must be %s%s (as in class %s)",
++              "Type of %s::$%s must be %s (as in class %s)",
+               ZSTR_VAL(child->ce->name),
+               ZSTR_VAL(child->name),
 -              ZEND_TYPE_ALLOW_NULL(parent->type) ? "?" : "",
 -              ZEND_TYPE_IS_CLASS(parent->type)
 -                      ? ZSTR_VAL(ZEND_TYPE_IS_CE(parent->type) ? ZEND_TYPE_CE(parent->type)->name : resolve_class_name(parent->ce, ZEND_TYPE_NAME(parent->type)))
 -                      : zend_get_type_by_const(ZEND_TYPE_CODE(parent->type)),
++              ZSTR_VAL(type_str),
+               ZSTR_VAL(parent->ce->name));
  }
  
  static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
@@@ -2132,7 -2233,12 +2135,11 @@@ typedef struct 
                struct {
                        const zend_function *parent_fn;
                        const zend_function *child_fn;
 -                      zend_bool always_error;
                };
+               struct {
+                       const zend_property_info *parent_prop;
+                       const zend_property_info *child_prop;
+               };
        };
  } variance_obligation;
  
@@@ -2205,10 -2325,22 +2223,21 @@@ static int check_variance_obligation(zv
                                return ZEND_HASH_APPLY_KEEP;
                        }
                        ZEND_ASSERT(status == INHERITANCE_ERROR);
 -                      emit_incompatible_method_error_or_warning(
 -                              obligation->child_fn, obligation->parent_fn, status, unresolved_class,
 -                              obligation->always_error);
 +                      emit_incompatible_method_error(
 +                              obligation->child_fn, obligation->parent_fn, status, unresolved_class);
                }
                /* Either the compatibility check was successful or only threw a warning. */
+       } else {
+               ZEND_ASSERT(obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY);
+               inheritance_status status =
+                       property_types_compatible(obligation->parent_prop, obligation->child_prop);
+               if (status != INHERITANCE_SUCCESS) {
+                       if (status == INHERITANCE_UNRESOLVED) {
+                               return ZEND_HASH_APPLY_KEEP;
+                       }
+                       ZEND_ASSERT(status == INHERITANCE_ERROR);
+                       emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
+               }
        }
        return ZEND_HASH_APPLY_REMOVE;
  }
@@@ -2261,15 -2393,19 +2290,18 @@@ static void report_variance_errors(zend
                inheritance_status status;
                zend_string *unresolved_class;
  
-               /* There should not be any unresolved parents at this point. */
-               ZEND_ASSERT(obligation->type == OBLIGATION_COMPATIBILITY);
-               /* Just used to fetch the unresolved_class in this case. */
-               status = zend_do_perform_implementation_check(
-                       &unresolved_class, obligation->child_fn, obligation->parent_fn);
-               ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
-               emit_incompatible_method_error(
-                       obligation->child_fn, obligation->parent_fn, status, unresolved_class);
+               if (obligation->type == OBLIGATION_COMPATIBILITY) {
+                       /* Just used to fetch the unresolved_class in this case. */
+                       status = zend_do_perform_implementation_check(
+                               &unresolved_class, obligation->child_fn, obligation->parent_fn);
+                       ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
 -                      emit_incompatible_method_error_or_warning(
 -                              obligation->child_fn, obligation->parent_fn,
 -                              status, unresolved_class, obligation->always_error);
++                      emit_incompatible_method_error(
++                              obligation->child_fn, obligation->parent_fn, status, unresolved_class);
+               } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
+                       emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
+               } else {
+                       zend_error_noreturn(E_CORE_ERROR, "Bug #78647");
+               }
        } ZEND_HASH_FOREACH_END();
  
        /* Only warnings were thrown above -- that means that there are incompatibilities, but only
@@@ -2377,8 -2513,10 +2409,9 @@@ ZEND_API int zend_do_link_class(zend_cl
  /* Check whether early binding is prevented due to unresolved types in inheritance checks. */
  static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
  {
 -      inheritance_status ret = INHERITANCE_SUCCESS;
        zend_string *key;
        zend_function *parent_func;
+       zend_property_info *parent_info;
  
        ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
                zval *zv = zend_hash_find_ex(&ce->function_table, key, 1);
                }
        } ZEND_HASH_FOREACH_END();
  
 -                                      if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
 -                                              return INHERITANCE_UNRESOLVED;
 -                                      }
 -                                      ZEND_ASSERT(status == INHERITANCE_ERROR);
 -                                      ret = INHERITANCE_ERROR;
+       ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
+               zval *zv;
+               if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
+                       continue;
+               }
+               zv = zend_hash_find_ex(&ce->properties_info, key, 1);
+               if (zv) {
+                       zend_property_info *child_info = Z_PTR_P(zv);
+                       if (ZEND_TYPE_IS_SET(child_info->type)) {
+                               inheritance_status status = property_types_compatible(parent_info, child_info);
+                               if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
 -      return ret;
++                                      return status;
+                               }
+                       }
+               }
+       } ZEND_HASH_FOREACH_END();
 +      return INHERITANCE_SUCCESS;
  }
  /* }}} */