@@ -1149,23 +1149,76 @@ 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+ uint32_t 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+ // TODO: bound_generic_types is null
1194+ bound_generic_types = zend_hash_find_ptr_lc (Z_OBJCE_P (arg )-> bound_types , ce -> name );
1195+ if (!bound_generic_types
1196+ || zend_hash_num_elements (bound_generic_types ) != ce -> num_generic_parameters
1197+ /* -1 because the class name must be excluded */
1198+ || zend_hash_num_elements (bound_generic_types ) != ZEND_TYPE_LIST (* type )-> num_types - 1
1199+ ) {
1200+ return false;
1201+ }
1202+ continue ;
1203+ }
1204+ ZEND_ASSERT (ce );
1205+ ZEND_ASSERT (bound_generic_types );
1206+ const zend_type * bound_type = zend_hash_index_find_ptr (bound_generic_types , inner_type ++ );
1207+ ZEND_ASSERT (bound_type );
1208+ if (!zend_type_is_equal (* list_type , * bound_type )) {
1209+ return false;
1210+ }
1211+ } ZEND_TYPE_LIST_FOREACH_END ();
1212+ } else if (ZEND_TYPE_IS_INTERSECTION (* type )) {
11601213 return zend_check_intersection_type_from_list (ZEND_TYPE_LIST (* type ), Z_OBJCE_P (arg ));
11611214 } else {
1162- const zend_type * list_type ;
1163- ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (* type ), list_type ) {
1215+ ZEND_TYPE_LIST_FOREACH (ZEND_TYPE_LIST (* type ), const zend_type * list_type ) {
11641216 if (ZEND_TYPE_IS_INTERSECTION (* list_type )) {
11651217 if (zend_check_intersection_type_from_list (ZEND_TYPE_LIST (* list_type ), Z_OBJCE_P (arg ))) {
11661218 return true;
11671219 }
11681220 } else {
1221+ /* TODO: Handle generic, or is this actually prevented ? */
11691222 ZEND_ASSERT (!ZEND_TYPE_HAS_LIST (* list_type ));
11701223 ce = zend_fetch_ce_from_type (list_type );
11711224 /* Instance of a single type part of a union is sufficient to pass the type check */
0 commit comments