@@ -1149,23 +1149,77 @@ static bool zend_check_intersection_type_from_list(
11491149 return true;
11501150}
11511151
1152+ static bool zend_type_is_equal (zend_type given_type , zend_type constraint_type ) {
1153+ if (ZEND_TYPE_PURE_MASK (given_type ) != ZEND_TYPE_PURE_MASK (constraint_type )) {
1154+ return false;
1155+ }
1156+ if (ZEND_TYPE_HAS_NAME (given_type )) {
1157+ ZEND_ASSERT (ZEND_TYPE_HAS_NAME (constraint_type ));
1158+ return zend_string_equals (ZEND_TYPE_NAME (given_type ), ZEND_TYPE_NAME (constraint_type ));
1159+ } else if (ZEND_TYPE_HAS_LIST (given_type )) {
1160+ ZEND_ASSERT (ZEND_TYPE_HAS_LIST (constraint_type ));
1161+ const zend_type_list * given_list_type = ZEND_TYPE_LIST (given_type );
1162+ const zend_type_list * constraint_list_type = ZEND_TYPE_LIST (constraint_type );
1163+ for (uint32_t list_type_index = 0 ; list_type_index < given_list_type -> num_types ; list_type_index ++ ) {
1164+ zend_type inner_given_type = given_list_type -> types [list_type_index ];
1165+ zend_type inner_constraint_type = constraint_list_type -> types [list_type_index ];
1166+ if (!zend_type_is_equal (inner_given_type , inner_constraint_type )) {
1167+ return false;
1168+ }
1169+ }
1170+ return true;
1171+ }
1172+ return true;
1173+ }
1174+
11521175static zend_always_inline bool zend_check_type_slow (
11531176 const zend_type * type , zval * arg , const zend_reference * ref ,
11541177 bool is_return_type , bool is_internal )
11551178{
11561179 if (ZEND_TYPE_IS_COMPLEX (* type ) && EXPECTED (Z_TYPE_P (arg ) == IS_OBJECT )) {
1157- zend_class_entry * ce ;
1180+ const zend_class_entry * ce ;
11581181 if (UNEXPECTED (ZEND_TYPE_HAS_LIST (* type ))) {
1159- if (ZEND_TYPE_IS_INTERSECTION (* type )) {
1182+ if (ZEND_TYPE_IS_NAME_WITH_GENERIC_TYPES (* type )) {
1183+ zend_ulong inner_type = 0 ;
1184+ bool is_ce = true;
1185+ const HashTable * bound_generic_types = NULL ;
1186+ ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (* type ), const zend_type * list_type ) {
1187+ if (is_ce ) {
1188+ is_ce = false;
1189+ ce = zend_fetch_ce_from_type (list_type );
1190+ if (!ce || !instanceof_function (Z_OBJCE_P (arg ), ce )) {
1191+ return false;
1192+ }
1193+ bound_generic_types = zend_hash_find_ptr_lc (Z_OBJCE_P (arg )-> bound_types , ce -> name );
1194+ if (!bound_generic_types
1195+ || zend_hash_num_elements (bound_generic_types ) != ce -> num_generic_parameters
1196+ /* -1 because the class name must be excluded */
1197+ || zend_hash_num_elements (bound_generic_types ) != ZEND_TYPE_LIST (* type )-> num_types - 1
1198+ ) {
1199+ return false;
1200+ }
1201+ continue ;
1202+ }
1203+ ZEND_ASSERT (ce );
1204+ ZEND_ASSERT (bound_generic_types );
1205+ const zend_type * bound_type = zend_hash_index_find_ptr (bound_generic_types , inner_type ++ );
1206+ ZEND_ASSERT (bound_type );
1207+ if (!zend_type_is_equal (* list_type , * bound_type )) {
1208+ return false;
1209+ }
1210+ } ZEND_TYPE_LIST_FOREACH_END ();
1211+ /* TODO: Should this actually continue outside the loop */
1212+ return true;
1213+ } else if (ZEND_TYPE_IS_INTERSECTION (* type )) {
11601214 return zend_check_intersection_type_from_list (ZEND_TYPE_LIST (* type ), Z_OBJCE_P (arg ));
11611215 } else {
1162- const zend_type * list_type ;
1163- ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (* type ), list_type ) {
1216+ ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (* type ), const zend_type * list_type ) {
11641217 if (ZEND_TYPE_IS_INTERSECTION (* list_type )) {
11651218 if (zend_check_intersection_type_from_list (ZEND_TYPE_LIST (* list_type ), Z_OBJCE_P (arg ))) {
11661219 return true;
11671220 }
11681221 } else {
1222+ /* TODO: Handle generic, or is this actually prevented ? */
11691223 ZEND_ASSERT (!ZEND_TYPE_HAS_LIST (* list_type ));
11701224 ce = zend_fetch_ce_from_type (list_type );
11711225 /* Instance of a single type part of a union is sufficient to pass the type check */
0 commit comments