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) /* {{{ */
{
}
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;
/* 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) /* {{{ */
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;
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;
}
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
/* 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;
}
/* }}} */