@@ -685,12 +685,14 @@ static inheritance_status zend_is_type_subtype_of_generic_type(
685
685
zend_class_entry * generic_type_scope ,
686
686
const zend_type * generic_type_ptr
687
687
) {
688
+ ZEND_ASSERT (concrete_scope -> bound_types );
688
689
const zend_type generic_type = * generic_type_ptr ;
690
+ const HashTable * bound_generic_types = zend_hash_find_ptr_lc (concrete_scope -> bound_types , generic_type_scope -> name );
689
691
690
- ZEND_ASSERT (CG ( bound_generic_types ) && "Have generic type" );
692
+ ZEND_ASSERT (bound_generic_types && "Have generic type" );
691
693
ZEND_ASSERT (ZEND_TYPE_HAS_NAME (generic_type ));
692
694
693
- const zend_type * bound_type_ptr = zend_hash_find_ptr (CG ( bound_generic_types ) , ZEND_TYPE_NAME (generic_type ));
695
+ const zend_type * bound_type_ptr = zend_hash_find_ptr (bound_generic_types , ZEND_TYPE_NAME (generic_type ));
694
696
ZEND_ASSERT (bound_type_ptr != NULL );
695
697
/* Generic type must be invariant */
696
698
const inheritance_status sub_type_status = zend_perform_covariant_type_check (
@@ -1638,6 +1640,57 @@ static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry
1638
1640
}
1639
1641
/* }}} */
1640
1642
1643
+ // TODO Merge with the one in zend_compile
1644
+ static void zend_types_ht_dtor (zval * ptr ) {
1645
+ zend_type * type = Z_PTR_P (ptr );
1646
+ // TODO Figure out persistency?
1647
+ zend_type_release (* type , false);
1648
+ efree (type );
1649
+ }
1650
+
1651
+ static void interface_bind_generic_types_for_interfaces (zend_class_entry * ce , const zend_class_entry * iface ) {
1652
+ zend_string * iface_lc_name = zend_string_tolower (iface -> name );
1653
+ const HashTable * ce_bound_types = ce -> bound_types ? zend_hash_find_ptr (ce -> bound_types , iface_lc_name ) : NULL ;
1654
+ for (uint32_t i = 0 ; i < iface -> num_interfaces ; i ++ ) {
1655
+ zend_class_entry * entry = iface -> interfaces [i ];
1656
+ /* Bind generic types */
1657
+ /* We need to propagate the bound generic parameters to the inherited interfaces */
1658
+ if (entry -> num_generic_parameters == 0 ) {
1659
+ continue ;
1660
+ }
1661
+ zend_string * inherited_iface_lc_name = zend_string_tolower (entry -> name );
1662
+ const HashTable * interface_bound_types = zend_hash_find_ptr (iface -> bound_types , inherited_iface_lc_name );
1663
+ HashTable * ce_bound_types_to_inherited_iface = zend_hash_find_ptr (ce -> bound_types , inherited_iface_lc_name );
1664
+ ZEND_ASSERT (interface_bound_types != NULL && "This must exist at this point" );
1665
+ if (ce_bound_types_to_inherited_iface == NULL ) {
1666
+ ALLOC_HASHTABLE (ce_bound_types_to_inherited_iface );
1667
+ zend_hash_init (ce_bound_types_to_inherited_iface , entry -> num_generic_parameters , NULL , zend_types_ht_dtor , false /* todo depend on internal or not */ );
1668
+ zend_hash_add_new_ptr (ce -> bound_types , inherited_iface_lc_name , ce_bound_types_to_inherited_iface );
1669
+ }
1670
+ for (
1671
+ uint32_t inherited_iface_generic_param_index = 0 ;
1672
+ inherited_iface_generic_param_index < entry -> num_generic_parameters ;
1673
+ inherited_iface_generic_param_index ++
1674
+ ) {
1675
+ const zend_generic_parameter * inherited_generic_parameter = & entry -> generic_parameters [inherited_iface_generic_param_index ];
1676
+ const zend_type * iface_bound_type_ptr = zend_hash_index_find_ptr (interface_bound_types , inherited_iface_generic_param_index );
1677
+ ZEND_ASSERT (iface_bound_type_ptr != NULL );
1678
+ zend_type bound_type ;
1679
+ if (ZEND_TYPE_IS_ASSOCIATED (* iface_bound_type_ptr )) {
1680
+ memcpy (& bound_type , zend_hash_find_ptr (ce_bound_types , ZEND_TYPE_NAME (* iface_bound_type_ptr )), sizeof (zend_type ));
1681
+ } else {
1682
+ bound_type = * iface_bound_type_ptr ;
1683
+ }
1684
+ /* Deep type copy */
1685
+ zend_type_copy_ctor (& bound_type , true, false);
1686
+ zend_hash_add_mem (ce_bound_types_to_inherited_iface , inherited_generic_parameter -> name ,
1687
+ & bound_type , sizeof (bound_type ));
1688
+ }
1689
+ zend_string_release_ex (inherited_iface_lc_name , false);
1690
+ }
1691
+ zend_string_release_ex (iface_lc_name , false);
1692
+ }
1693
+
1641
1694
static void zend_do_inherit_interfaces (zend_class_entry * ce , const zend_class_entry * iface ) /* {{{ */
1642
1695
{
1643
1696
/* expects interface to be contained in ce's interface list already */
@@ -1656,6 +1709,7 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_en
1656
1709
zend_class_entry * entry = iface -> interfaces [if_num ];
1657
1710
for (i = 0 ; i < ce_num ; i ++ ) {
1658
1711
if (ce -> interfaces [i ] == entry ) {
1712
+ // TODO Check bound generic types match? Or is this done before?
1659
1713
break ;
1660
1714
}
1661
1715
}
@@ -2222,7 +2276,7 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2222
2276
ZSTR_VAL (iface -> name )
2223
2277
);
2224
2278
}
2225
- const HashTable * bound_types = zend_hash_find_ptr_lc (ce -> bound_types , iface -> name );
2279
+ HashTable * bound_types = zend_hash_find_ptr_lc (ce -> bound_types , iface -> name );
2226
2280
if (UNEXPECTED (bound_types == NULL )) {
2227
2281
zend_error_noreturn (E_COMPILE_ERROR ,
2228
2282
"Cannot implement %s as it has generic parameters which are not specified" ,
@@ -2238,9 +2292,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2238
2292
iface -> num_generic_parameters
2239
2293
);
2240
2294
}
2241
- HashTable * ht = emalloc (sizeof (HashTable ));
2242
- zend_hash_init (ht , num_bound_types , NULL , NULL , false);
2243
- CG (bound_generic_types ) = ht ;
2244
2295
for (uint32_t i = 0 ; i < num_bound_types ; i ++ ) {
2245
2296
const zend_generic_parameter * generic_parameter = & iface -> generic_parameters [i ];
2246
2297
const zend_type * generic_constraint = & generic_parameter -> constraint ;
@@ -2260,7 +2311,14 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2260
2311
}
2261
2312
const zend_type * current_ce_generic_type_constraint = & current_ce_generic_parameter -> constraint ;
2262
2313
ZEND_ASSERT (current_ce_generic_type_constraint != NULL );
2263
- if (zend_perform_covariant_type_check (ce , current_ce_generic_type_constraint , iface , generic_constraint ) != INHERITANCE_SUCCESS ) {
2314
+ if (
2315
+ zend_perform_covariant_type_check (
2316
+ ce ,
2317
+ current_ce_generic_type_constraint ,
2318
+ iface ,
2319
+ generic_constraint
2320
+ ) != INHERITANCE_SUCCESS
2321
+ ) {
2264
2322
zend_string * current_ce_constraint_type_str = zend_type_to_string (* current_ce_generic_type_constraint );
2265
2323
zend_string * constraint_type_str = zend_type_to_string (generic_parameter -> constraint );
2266
2324
zend_error_noreturn (E_COMPILE_ERROR ,
@@ -2276,8 +2334,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2276
2334
zend_string_release (constraint_type_str );
2277
2335
return ;
2278
2336
}
2279
- /* Loosing const qualifier here is OK because this hashtable never frees or does anything with the value */
2280
- zend_hash_add_new_ptr (ht , generic_parameter -> name , (void * )current_ce_generic_type_constraint );
2281
2337
break ;
2282
2338
}
2283
2339
} else {
@@ -2295,10 +2351,17 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2295
2351
zend_string_release (constraint_type_str );
2296
2352
return ;
2297
2353
}
2298
- zend_hash_add_new_ptr (ht , generic_parameter -> name , bound_type_ptr );
2354
+ /* Change key from index to generic parameter name */
2355
+ /* Deep type copy */
2356
+ zend_type bound_type = * bound_type_ptr ;
2357
+ zend_type_copy_ctor (& bound_type , true, false);
2358
+ zend_hash_add_mem (bound_types , generic_parameter -> name ,
2359
+ & bound_type , sizeof (bound_type ));
2360
+ //zend_hash_index_del(bound_types, i);
2299
2361
}
2300
2362
}
2301
2363
}
2364
+ interface_bind_generic_types_for_interfaces (ce , iface );
2302
2365
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR (& iface -> constants_table , key , c ) {
2303
2366
do_inherit_iface_constant (key , c , ce , iface );
2304
2367
} ZEND_HASH_FOREACH_END ();
@@ -2320,11 +2383,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
2320
2383
if (iface -> num_interfaces ) {
2321
2384
zend_do_inherit_interfaces (ce , iface );
2322
2385
}
2323
- if (CG (bound_generic_types )) {
2324
- zend_hash_destroy (CG (bound_generic_types ));
2325
- efree (CG (bound_generic_types ));
2326
- CG (bound_generic_types ) = NULL ;
2327
- }
2328
2386
}
2329
2387
/* }}} */
2330
2388
0 commit comments