@@ -2328,61 +2328,74 @@ ZEND_ATTRIBUTE_NONNULL static void bind_generic_types_for_inherited_interfaces(z
2328
2328
ZEND_HASH_FOREACH_STR_KEY_PTR (iface_bound_types , lc_inherited_iface_name , interface_bound_types_for_inherited_iface ) {
2329
2329
ZEND_ASSERT (lc_inherited_iface_name != NULL );
2330
2330
2331
- zend_string * generic_param_name = NULL ;
2332
- zend_ulong generic_param_index = 0 ;
2333
- zend_type * bound_type_ptr = NULL ;
2334
- HashTable * ce_bound_types_for_inherited_iface = NULL ;
2335
- ALLOC_HASHTABLE (ce_bound_types_for_inherited_iface );
2336
- zend_hash_init (
2337
- ce_bound_types_for_inherited_iface ,
2338
- zend_hash_num_elements (interface_bound_types_for_inherited_iface ),
2339
- NULL ,
2340
- zend_types_ht_dtor ,
2341
- false /* TODO depends on internals */
2342
- );
2343
- ZEND_HASH_FOREACH_KEY_PTR (interface_bound_types_for_inherited_iface , generic_param_index , generic_param_name , bound_type_ptr ) {
2344
- ZEND_ASSERT (generic_param_name == NULL ); // TODO Change foreach macro;
2345
- zend_type bound_type = * bound_type_ptr ;
2346
- if (ZEND_TYPE_IS_GENERIC_PARAM_NAME (bound_type )) {
2347
- ZEND_ASSERT (ce_bound_types_for_direct_iface != NULL &&
2348
- "If a bound type is generic then we must have bound types for the current interface" );
2349
- const zend_type * ce_bound_type_ptr = zend_hash_index_find_ptr (ce_bound_types_for_direct_iface , bound_type_ptr -> generic_param_index );
2350
- ZEND_ASSERT (ce_bound_type_ptr != NULL );
2351
- bound_type = * ce_bound_type_ptr ;
2352
- }
2353
-
2354
- zend_type_copy_ctor (& bound_type , true, false /* TODO Depends on internal or not? */ );
2355
- zend_hash_index_add_mem (ce_bound_types_for_inherited_iface , generic_param_index ,
2356
- & bound_type , sizeof (bound_type ));
2357
- } ZEND_HASH_FOREACH_END ();
2358
-
2359
2331
const HashTable * existing_bound_types_for_inherited_iface = zend_hash_find_ptr (ce -> bound_types , lc_inherited_iface_name );
2360
2332
if (EXPECTED (existing_bound_types_for_inherited_iface == NULL )) {
2333
+ HashTable * ce_bound_types_for_inherited_iface = NULL ;
2334
+ ALLOC_HASHTABLE (ce_bound_types_for_inherited_iface );
2335
+ zend_hash_init (
2336
+ ce_bound_types_for_inherited_iface ,
2337
+ zend_hash_num_elements (interface_bound_types_for_inherited_iface ),
2338
+ NULL ,
2339
+ zend_types_ht_dtor ,
2340
+ false /* TODO depends on internals */
2341
+ );
2342
+
2343
+ zend_ulong generic_param_index = 0 ;
2344
+ const zend_type * bound_type_ptr = NULL ;
2345
+ ZEND_HASH_FOREACH_NUM_KEY_PTR (interface_bound_types_for_inherited_iface , generic_param_index , bound_type_ptr ) {
2346
+ zend_type bound_type = * bound_type_ptr ;
2347
+ if (ZEND_TYPE_IS_GENERIC_PARAM_NAME (bound_type )) {
2348
+ ZEND_ASSERT (ce_bound_types_for_direct_iface != NULL &&
2349
+ "If a bound type is generic then we must have bound types for the current interface" );
2350
+ const zend_type * ce_bound_type_ptr = zend_hash_index_find_ptr (ce_bound_types_for_direct_iface , bound_type_ptr -> generic_param_index );
2351
+ ZEND_ASSERT (ce_bound_type_ptr != NULL );
2352
+ bound_type = * ce_bound_type_ptr ;
2353
+ }
2354
+
2355
+ zend_type_copy_ctor (& bound_type , true, false /* TODO Depends on internal or not? */ );
2356
+ zend_hash_index_add_mem (ce_bound_types_for_inherited_iface , generic_param_index ,
2357
+ & bound_type , sizeof (bound_type ));
2358
+ } ZEND_HASH_FOREACH_END ();
2359
+ zend_hash_add_new_ptr (ce -> bound_types , lc_inherited_iface_name , ce_bound_types_for_inherited_iface );
2361
2360
} else {
2362
- zend_ulong idx ;
2363
- zend_string * bound_name ;
2364
- const zend_type * ptr ;
2365
- ZEND_HASH_FOREACH_KEY_PTR (existing_bound_types_for_inherited_iface , idx , bound_name , ptr ) {
2366
- if (bound_name != NULL ) {
2367
- continue ;
2361
+ const uint32_t num_generic_types = zend_hash_num_elements (interface_bound_types_for_inherited_iface );
2362
+ ZEND_ASSERT (zend_hash_num_elements (existing_bound_types_for_inherited_iface ) == num_generic_types && "Existing bound types should have errored before" );
2363
+
2364
+ for (zend_ulong bound_type_index = 0 ; bound_type_index < num_generic_types ; bound_type_index ++ ) {
2365
+ const zend_type * iface_bound_type_ptr = zend_hash_index_find_ptr (interface_bound_types_for_inherited_iface , bound_type_index );
2366
+ const zend_type * ce_bound_type_ptr = zend_hash_index_find_ptr (existing_bound_types_for_inherited_iface , bound_type_index );
2367
+ ZEND_ASSERT (iface_bound_type_ptr != NULL && ce_bound_type_ptr != NULL );
2368
+ if (ZEND_TYPE_IS_GENERIC_PARAM_NAME (* iface_bound_type_ptr )) {
2369
+ iface_bound_type_ptr = zend_hash_index_find_ptr (ce_bound_types_for_direct_iface , iface_bound_type_ptr -> generic_param_index );
2370
+ ZEND_ASSERT (iface_bound_type_ptr != NULL );
2368
2371
}
2369
- const zend_type t1 = * ptr ;
2370
- const zend_type * ptr2 = zend_hash_index_find_ptr (ce_bound_types_for_inherited_iface , idx );
2371
- ZEND_ASSERT (ptr2 != NULL );
2372
- const zend_type t2 = * ptr2 ;
2372
+ const zend_type t1 = * iface_bound_type_ptr ;
2373
+ const zend_type t2 = * ce_bound_type_ptr ;
2373
2374
if (
2374
2375
ZEND_TYPE_FULL_MASK (t1 ) != ZEND_TYPE_FULL_MASK (t2 )
2375
2376
|| (ZEND_TYPE_HAS_NAME (t1 ) && !zend_string_equals (ZEND_TYPE_NAME (t1 ), ZEND_TYPE_NAME (t2 )))
2376
2377
// || ZEND_TYPE_HAS_LIST(t1) && TODO Check list types are equal
2377
2378
) {
2378
- // TODO Improve this error message
2379
- zend_error_noreturn (E_COMPILE_ERROR , "Bound types for implicitly and explicitly implemented interfaces must match" );
2379
+ const zend_class_entry * inherited_iface = zend_hash_find_ptr (CG (class_table ), lc_inherited_iface_name );
2380
+ ZEND_ASSERT (inherited_iface != NULL );
2381
+ const zend_generic_parameter param = inherited_iface -> generic_parameters [bound_type_index ];
2382
+
2383
+ zend_string * ce_bound_type_str = zend_type_to_string_resolved (t2 , ce , NULL );
2384
+ zend_string * iface_bound_type_str = zend_type_to_string_resolved (t1 , iface , NULL );
2385
+ zend_error_noreturn (E_COMPILE_ERROR ,
2386
+ "Bound type %s for interface %s implemented explicitly in %s with type %s must match the implicitly bound type %s from interface %s" ,
2387
+ ZSTR_VAL (param .name ),
2388
+ ZSTR_VAL (inherited_iface -> name ),
2389
+ ZSTR_VAL (ce -> name ),
2390
+ ZSTR_VAL (ce_bound_type_str ),
2391
+ ZSTR_VAL (iface_bound_type_str ),
2392
+ ZSTR_VAL (iface -> name )
2393
+ );
2394
+ zend_string_release_ex (ce_bound_type_str , false);
2395
+ zend_string_release_ex (iface_bound_type_str , false);
2380
2396
}
2381
- } ZEND_HASH_FOREACH_END ();
2382
- /* Remove current ones as they may be incomplete without the type name binding */
2383
- zend_hash_del (ce -> bound_types , lc_inherited_iface_name );
2397
+ }
2384
2398
}
2385
- zend_hash_add_new_ptr (ce -> bound_types , lc_inherited_iface_name , ce_bound_types_for_inherited_iface );
2386
2399
} ZEND_HASH_FOREACH_END ();
2387
2400
}
2388
2401
0 commit comments