Skip to content

Commit 62695d8

Browse files
committed
Unify early exit status handling, add comments
1 parent 2170f7b commit 62695d8

File tree

1 file changed

+38
-53
lines changed

1 file changed

+38
-53
lines changed

Zend/zend_inheritance.c

Lines changed: 38 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -399,9 +399,11 @@ static void track_class_dependency(zend_class_entry *ce, zend_string *class_name
399399
zend_hash_add_ptr(ht, class_name, ce);
400400
}
401401

402-
static inheritance_status zend_perform_intersection_covariant_class_type_check(
403-
zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce,
402+
/* Check whether any type in fe_type is a subtype of the proto class.
403+
* This is independently of whether fe_type is a union or intersection. */
404+
static inheritance_status zend_is_any_type_subtype_of_class(
404405
zend_class_entry *fe_scope, zend_type fe_type,
406+
zend_class_entry *proto_scope, zend_string *proto_class_name, zend_class_entry *proto_ce,
405407
bool register_unresolved)
406408
{
407409
bool have_unresolved = false;
@@ -447,7 +449,7 @@ static inheritance_status zend_perform_intersection_covariant_class_type_check(
447449
}
448450

449451
/* Check whether a single class proto type is a subtype of a potentially complex fe_type. */
450-
static inheritance_status zend_perform_covariant_class_type_check(
452+
static inheritance_status zend_is_class_subtype_of_type(
451453
zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce,
452454
zend_class_entry *proto_scope, zend_type proto_type,
453455
bool register_unresolved) {
@@ -577,15 +579,16 @@ static inheritance_status zend_perform_covariant_type_check(
577579
}
578580

579581
zend_type *single_type;
580-
bool all_success = true;
582+
inheritance_status early_exit_status;
583+
bool have_unresolved = false;
581584

582-
/* If the child type is an intersection type then we need to loop over
583-
* the parents first. For intersection types, loop over the parent types first
584-
* as the child can add types, however none of them can be a supertype of
585-
* a parent type. */
586585
if (ZEND_TYPE_IS_INTERSECTION(fe_type)) {
587-
bool parent_union_has_unresolved = false;
588-
/* First try to check whether we can succeed without resolving anything */
586+
/* U_1&...&U_n < V_1&...&V_m if forall V_j. exists U_i. U_i < V_j.
587+
* U_1&...&U_n < V_1|...|V_m if exists V_j. exists U_i. U_i < V_j.
588+
* As such, we need to iterate over proto_type (V_j) first and use a different
589+
* quantifier depending on whether fe_type is a union or an intersection. */
590+
early_exit_status =
591+
ZEND_TYPE_IS_INTERSECTION(proto_type) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS;
589592
ZEND_TYPE_FOREACH(proto_type, single_type) {
590593
inheritance_status status;
591594
zend_string *proto_class_name;
@@ -602,39 +605,22 @@ static inheritance_status zend_perform_covariant_type_check(
602605
continue;
603606
}
604607

605-
status = zend_perform_intersection_covariant_class_type_check(
606-
proto_scope, proto_class_name, proto_ce,
607-
fe_scope, fe_type, /* register_unresolved */ false);
608-
609-
/* If the parent is a union type then the intersection type must only be
610-
* a subtype of one of them */
611-
if (ZEND_TYPE_IS_UNION(proto_type)) {
612-
if (status == INHERITANCE_SUCCESS) {
613-
return INHERITANCE_SUCCESS;
614-
}
615-
if (status == INHERITANCE_UNRESOLVED) {
616-
all_success = false;
617-
}
618-
} else {
619-
if (status == INHERITANCE_ERROR) {
620-
return INHERITANCE_ERROR;
621-
}
622-
if (status != INHERITANCE_SUCCESS) {
623-
ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
624-
parent_union_has_unresolved = true;
625-
all_success = false;
626-
}
608+
status = zend_is_any_type_subtype_of_class(
609+
fe_scope, fe_type, proto_scope, proto_class_name, proto_ce,
610+
/* register_unresolved */ false);
611+
if (status == early_exit_status) {
612+
return status;
613+
}
614+
if (status == INHERITANCE_UNRESOLVED) {
615+
have_unresolved = true;
627616
}
628617
} ZEND_TYPE_FOREACH_END();
629-
630-
/* Reaching this means either the child intersection type is a valid/unresolved
631-
* subtype of a parent single/intersection type, either it is an INvalid subtype
632-
* when the parent is a union or it is unresolved, we check which case this is */
633-
if (ZEND_TYPE_IS_UNION(proto_type) && !parent_union_has_unresolved) {
634-
return INHERITANCE_ERROR;
635-
}
636618
} else {
637-
/* First try to check whether we can succeed without resolving anything */
619+
/* U_1|...|U_n < V_1|...|V_m if forall U_i. exists V_j. U_i < V_j.
620+
* U_1|...|U_n < V_1&...&V_m if forall U_i. forall V_j. U_i < V_j.
621+
* We need to iterate over fe_type (U_i) first and the logic is independent of
622+
* whether proto_type is a union or intersection (only the inner check differs). */
623+
early_exit_status = INHERITANCE_ERROR;
638624
ZEND_TYPE_FOREACH(fe_type, single_type) {
639625
inheritance_status status;
640626
zend_string *fe_class_name;
@@ -649,21 +635,20 @@ static inheritance_status zend_perform_covariant_type_check(
649635
continue;
650636
}
651637

652-
status = zend_perform_covariant_class_type_check(fe_scope,
653-
fe_class_name, fe_ce, proto_scope, proto_type,
638+
status = zend_is_class_subtype_of_type(
639+
fe_scope, fe_class_name, fe_ce, proto_scope, proto_type,
654640
/* register_unresolved */ false);
655-
if (status == INHERITANCE_ERROR) {
656-
return INHERITANCE_ERROR;
641+
if (status == early_exit_status) {
642+
return early_exit_status;
657643
}
658-
if (status != INHERITANCE_SUCCESS) {
659-
all_success = 0;
644+
if (status == INHERITANCE_UNRESOLVED) {
645+
have_unresolved = true;
660646
}
661647
} ZEND_TYPE_FOREACH_END();
662648
}
663649

664-
/* All individual checks succeeded, overall success */
665-
if (all_success) {
666-
return INHERITANCE_SUCCESS;
650+
if (!have_unresolved) {
651+
return early_exit_status == INHERITANCE_ERROR ? INHERITANCE_SUCCESS : INHERITANCE_ERROR;
667652
}
668653

669654
/* Register all classes that may have to be resolved */
@@ -683,8 +668,8 @@ static inheritance_status zend_perform_covariant_type_check(
683668
continue;
684669
}
685670

686-
zend_perform_intersection_covariant_class_type_check(proto_scope,
687-
proto_class_name, proto_ce, fe_scope, fe_type,
671+
zend_is_any_type_subtype_of_class(
672+
fe_scope, fe_type, proto_scope, proto_class_name, proto_ce,
688673
/* register_unresolved */ true);
689674
} ZEND_TYPE_FOREACH_END();
690675
} else {
@@ -701,8 +686,8 @@ static inheritance_status zend_perform_covariant_type_check(
701686
continue;
702687
}
703688

704-
zend_perform_covariant_class_type_check(fe_scope,
705-
fe_class_name, fe_ce, proto_scope, proto_type,
689+
zend_is_class_subtype_of_type(
690+
fe_scope, fe_class_name, fe_ce, proto_scope, proto_type,
706691
/* register_unresolved */ true);
707692
} ZEND_TYPE_FOREACH_END();
708693
}

0 commit comments

Comments
 (0)