Skip to content

Commit

Permalink
Combine variance obligation processing and error reporting
Browse files Browse the repository at this point in the history
I don't believe there's a reason anymore to first resolve all
delayed variance obligations, and then report errors if any are
left.  We can report errors directly when resolving obligations.
  • Loading branch information
nikic committed Nov 8, 2021
1 parent 904933e commit b969ce3
Showing 1 changed file with 2 additions and 52 deletions.
54 changes: 2 additions & 52 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -2441,8 +2441,7 @@ static void add_property_compatibility_obligation(

static void resolve_delayed_variance_obligations(zend_class_entry *ce);

static int check_variance_obligation(zval *zv) {
variance_obligation *obligation = Z_PTR_P(zv);
static void check_variance_obligation(variance_obligation *obligation) {
if (obligation->type == OBLIGATION_DEPENDENCY) {
zend_class_entry *dependency_ce = obligation->dependency_ce;
if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
Expand All @@ -2453,18 +2452,11 @@ static int check_variance_obligation(zval *zv) {
resolve_delayed_variance_obligations(dependency_ce);
CG(current_linking_class) = orig_linking_class;
}
if (!(dependency_ce->ce_flags & ZEND_ACC_LINKED)) {
return ZEND_HASH_APPLY_KEEP;
}
} else if (obligation->type == OBLIGATION_COMPATIBILITY) {
inheritance_status status = zend_do_perform_implementation_check(
&obligation->child_fn, obligation->child_scope,
&obligation->parent_fn, obligation->parent_scope);
if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
return ZEND_HASH_APPLY_KEEP;
}
ZEND_ASSERT(status == INHERITANCE_ERROR);
emit_incompatible_method_error(
&obligation->child_fn, obligation->child_scope,
&obligation->parent_fn, obligation->parent_scope, status);
Expand All @@ -2475,14 +2467,9 @@ static int check_variance_obligation(zval *zv) {
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;
}

static void load_delayed_classes(zend_class_entry *ce) {
Expand Down Expand Up @@ -2521,44 +2508,11 @@ static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
obligations = zend_hash_index_find_ptr(all_obligations, num_key);
ZEND_ASSERT(obligations != NULL);

zend_hash_apply(obligations, check_variance_obligation);
if (zend_hash_num_elements(obligations) == 0) {
ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
ce->ce_flags |= ZEND_ACC_LINKED;
zend_hash_index_del(all_obligations, num_key);
}
}

static void report_variance_errors(zend_class_entry *ce) {
HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
variance_obligation *obligation;
zend_ulong num_key = (zend_ulong) (uintptr_t) ce;

ZEND_ASSERT(all_obligations != NULL);
obligations = zend_hash_index_find_ptr(all_obligations, num_key);
ZEND_ASSERT(obligations != NULL);

ZEND_HASH_FOREACH_PTR(obligations, obligation) {
if (obligation->type == OBLIGATION_COMPATIBILITY) {
/* Just used to populate the delayed_autoloads table,
* which will be used when printing the "unresolved" error. */
inheritance_status status = zend_do_perform_implementation_check(
&obligation->child_fn, obligation->child_scope,
&obligation->parent_fn, obligation->parent_scope);
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
emit_incompatible_method_error(
&obligation->child_fn, obligation->child_scope,
&obligation->parent_fn, obligation->parent_scope, status);
} else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
} else {
/* Report variance errors of the dependency, which prevent it from being linked. */
report_variance_errors(obligation->dependency_ce);
}
check_variance_obligation(obligation);
} ZEND_HASH_FOREACH_END();

/* Only warnings were thrown above -- that means that there are incompatibilities, but only
* ones that we permit. Mark all classes with open obligations as fully linked. */
ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
ce->ce_flags |= ZEND_ACC_LINKED;
zend_hash_index_del(all_obligations, num_key);
Expand Down Expand Up @@ -2931,10 +2885,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
load_delayed_classes(ce);
if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
resolve_delayed_variance_obligations(ce);
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
CG(current_linking_class) = orig_linking_class;
report_variance_errors(ce);
}
}
if (ce->ce_flags & ZEND_ACC_CACHEABLE) {
ce->ce_flags &= ~ZEND_ACC_CACHEABLE;
Expand Down

0 comments on commit b969ce3

Please sign in to comment.