@@ -406,8 +406,7 @@ static void track_class_dependency(zend_class_entry *ce, zend_string *class_name
406406/* Check whether any type in the fe_type intersection type is a subtype of the proto class. */
407407static inheritance_status zend_is_intersection_subtype_of_class (
408408 zend_class_entry * fe_scope , zend_type fe_type ,
409- zend_class_entry * proto_scope , zend_string * proto_class_name , zend_class_entry * proto_ce ,
410- bool register_unresolved )
409+ zend_class_entry * proto_scope , zend_string * proto_class_name , zend_class_entry * proto_ce )
411410{
412411 ZEND_ASSERT (ZEND_TYPE_IS_INTERSECTION (fe_type ));
413412 bool have_unresolved = false;
@@ -425,11 +424,10 @@ static inheritance_status zend_is_intersection_subtype_of_class(
425424 return INHERITANCE_SUCCESS ;
426425 }
427426
428- if (!proto_ce ) proto_ce = lookup_class (proto_scope , proto_class_name , register_unresolved );
429- fe_ce =
430- lookup_class (fe_scope , fe_class_name , register_unresolved );
427+ if (!proto_ce ) proto_ce = lookup_class (proto_scope , proto_class_name );
428+ fe_ce = lookup_class (fe_scope , fe_class_name );
431429 } else if (ZEND_TYPE_HAS_CE (* single_type )) {
432- if (!proto_ce ) proto_ce = lookup_class (proto_scope , proto_class_name , register_unresolved );
430+ if (!proto_ce ) proto_ce = lookup_class (proto_scope , proto_class_name );
433431 fe_ce = ZEND_TYPE_CE (* single_type );
434432 } else {
435433 /* standard type in an intersection type is impossible,
@@ -533,6 +531,19 @@ static inheritance_status zend_is_class_subtype_of_type(
533531 return is_intersection ? INHERITANCE_SUCCESS : INHERITANCE_ERROR ;
534532}
535533
534+ static zend_string * get_class_from_type (
535+ zend_class_entry * * ce , zend_class_entry * scope , zend_type single_type ) {
536+ if (ZEND_TYPE_HAS_NAME (single_type )) {
537+ * ce = NULL ;
538+ return resolve_class_name (scope , ZEND_TYPE_NAME (single_type ));
539+ }
540+ if (ZEND_TYPE_HAS_CE (single_type )) {
541+ * ce = ZEND_TYPE_CE (single_type );
542+ return (* ce )-> name ;
543+ }
544+ return NULL ;
545+ }
546+
536547static void register_unresolved_classes (zend_class_entry * scope , zend_type type ) {
537548 zend_type * single_type ;
538549 ZEND_TYPE_FOREACH (type , single_type ) {
@@ -595,15 +606,26 @@ static inheritance_status zend_perform_covariant_type_check(
595606 bool have_unresolved = false;
596607
597608 if (ZEND_TYPE_IS_INTERSECTION (fe_type )) {
598- if (proto_type_mask & MAY_BE_OBJECT ) {
599- /* TODO We can't just return success here, because the class must be loaded. */
600- }
601- if (proto_type_mask & MAY_BE_ITERABLE ) {
602- /* TODO */
603- }
604- if (proto_type_mask ) {
605- /* An intersection type cannot be a subtype of other builtin types. */
606- return INHERITANCE_ERROR ;
609+ if (proto_type_mask & (MAY_BE_OBJECT |MAY_BE_ITERABLE )) {
610+ bool any_class = (proto_type_mask & MAY_BE_OBJECT ) != 0 ;
611+ ZEND_TYPE_FOREACH (fe_type , single_type ) {
612+ zend_class_entry * fe_ce ;
613+ zend_string * fe_class_name = get_class_from_type (& fe_ce , fe_scope , * single_type );
614+ if (!fe_class_name ) {
615+ continue ;
616+ }
617+ if (!fe_ce ) {
618+ fe_ce = lookup_class (fe_scope , fe_class_name );
619+ }
620+ if (fe_ce ) {
621+ if (any_class || unlinked_instanceof (fe_ce , zend_ce_traversable )) {
622+ track_class_dependency (fe_ce , fe_class_name );
623+ return INHERITANCE_SUCCESS ;
624+ }
625+ } else {
626+ have_unresolved = true;
627+ }
628+ } ZEND_TYPE_FOREACH_END ();
607629 }
608630
609631 /* U_1&...&U_n < V_1&...&V_m if forall V_j. exists U_i. U_i < V_j.
@@ -613,22 +635,15 @@ static inheritance_status zend_perform_covariant_type_check(
613635 early_exit_status =
614636 ZEND_TYPE_IS_INTERSECTION (proto_type ) ? INHERITANCE_ERROR : INHERITANCE_SUCCESS ;
615637 ZEND_TYPE_FOREACH (proto_type , single_type ) {
616- inheritance_status status ;
617- zend_string * proto_class_name ;
618- zend_class_entry * proto_ce = NULL ;
619-
620- if (ZEND_TYPE_HAS_NAME (* single_type )) {
621- proto_class_name = resolve_class_name (proto_scope , ZEND_TYPE_NAME (* single_type ));
622- } else if (ZEND_TYPE_HAS_CE (* single_type )) {
623- proto_ce = ZEND_TYPE_CE (* single_type );
624- proto_class_name = proto_ce -> name ;
625- } else {
638+ zend_class_entry * proto_ce ;
639+ zend_string * proto_class_name =
640+ get_class_from_type (& proto_ce , proto_scope , * single_type );
641+ if (!proto_class_name ) {
626642 continue ;
627643 }
628644
629- status = zend_is_intersection_subtype_of_class (
630- fe_scope , fe_type , proto_scope , proto_class_name , proto_ce ,
631- /* register_unresolved */ false);
645+ inheritance_status status = zend_is_intersection_subtype_of_class (
646+ fe_scope , fe_type , proto_scope , proto_class_name , proto_ce );
632647 if (status == early_exit_status ) {
633648 return status ;
634649 }
@@ -643,22 +658,14 @@ static inheritance_status zend_perform_covariant_type_check(
643658 * whether proto_type is a union or intersection (only the inner check differs). */
644659 early_exit_status = INHERITANCE_ERROR ;
645660 ZEND_TYPE_FOREACH (fe_type , single_type ) {
646- inheritance_status status ;
647- zend_string * fe_class_name ;
648- zend_class_entry * fe_ce = NULL ;
649-
650- if (ZEND_TYPE_HAS_NAME (* single_type )) {
651- fe_class_name = resolve_class_name (fe_scope , ZEND_TYPE_NAME (* single_type ));
652- } else if (ZEND_TYPE_HAS_CE (* single_type )) {
653- fe_ce = ZEND_TYPE_CE (* single_type );
654- fe_class_name = fe_ce -> name ;
655- } else {
661+ zend_class_entry * fe_ce ;
662+ zend_string * fe_class_name = get_class_from_type (& fe_ce , fe_scope , * single_type );
663+ if (!fe_class_name ) {
656664 continue ;
657665 }
658666
659- status = zend_is_class_subtype_of_type (
660- fe_scope , fe_class_name , fe_ce , proto_scope , proto_type ,
661- /* register_unresolved */ false);
667+ inheritance_status status = zend_is_class_subtype_of_type (
668+ fe_scope , fe_class_name , fe_ce , proto_scope , proto_type );
662669 if (status == early_exit_status ) {
663670 return early_exit_status ;
664671 }
0 commit comments