Skip to content

Commit 7c48c0b

Browse files
committed
Rewrite generic type binding for inherited interfaces
1 parent 0d8b7d3 commit 7c48c0b

File tree

2 files changed

+70
-56
lines changed

2 files changed

+70
-56
lines changed

Zend/tests/type_declarations/abstract_generics/extended_twice_interface_abstract_generic_types_basic.phpt

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,3 @@ class C implements I3<string> {
2525
DONE
2626
--EXPECT--
2727
DONE
28-
29-
30-
31-
Fatal error: CE: I3, Iface: I2, binding to Iface: I1, Generic type name: T2
32-
Binding generic types for CE: I2 for interface: I1
33-
Binding generic types for CE: I3 for interface: I2
34-
Binding generic types for CE: I3 for inherited interface: I1
35-
Binding generic types to generic type: T2 for inherited interface: I1

Zend/zend_inheritance.c

Lines changed: 70 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2198,7 +2198,12 @@ static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c,
21982198
}
21992199
/* }}} */
22002200

2201-
// TODO Merge with the one in zend_compile
2201+
// TODO Merge with the ones in zend_compile
2202+
static void zend_bound_types_ht_dtor(zval *ptr) {
2203+
HashTable *interface_bound_types = Z_PTR_P(ptr);
2204+
zend_hash_destroy(interface_bound_types);
2205+
efree(interface_bound_types);
2206+
}
22022207
static void zend_types_ht_dtor(zval *ptr) {
22032208
zend_type *type = Z_PTR_P(ptr);
22042209
// TODO Figure out persistency?
@@ -2207,46 +2212,66 @@ static void zend_types_ht_dtor(zval *ptr) {
22072212
}
22082213

22092214
ZEND_ATTRIBUTE_NONNULL static void bind_generic_types_for_inherited_interfaces(zend_class_entry *ce, const zend_class_entry *iface) {
2210-
zend_string *iface_lc_name = zend_string_tolower(iface->name);
2211-
const HashTable *ce_bound_types = ce->bound_types ? zend_hash_find_ptr(ce->bound_types, iface_lc_name) : NULL;
2212-
for (uint32_t i = 0; i < iface->num_interfaces; i++) {
2213-
const zend_class_entry *inherited_iface = iface->interfaces[i];
2214-
/* Bind generic types */
2215-
/* We need to propagate the bound generic parameters to the inherited interfaces */
2216-
if (inherited_iface->num_generic_parameters == 0) {
2217-
continue;
2215+
const HashTable *iface_bound_types = iface->bound_types;
2216+
if (iface_bound_types == NULL) {
2217+
#ifdef ZEND_DEBUG
2218+
for (uint32_t i = 0; i < iface->num_interfaces; i++) {
2219+
const zend_class_entry *inherited_iface = iface->interfaces[i];
2220+
ZEND_ASSERT(inherited_iface->num_generic_parameters == 0);
22182221
}
2219-
zend_string *inherited_iface_lc_name = zend_string_tolower(inherited_iface->name);
2220-
const HashTable *interface_bound_types = zend_hash_find_ptr(iface->bound_types, inherited_iface_lc_name);
2221-
HashTable *ce_bound_types_to_inherited_iface = zend_hash_find_ptr(ce->bound_types, inherited_iface_lc_name);
2222-
ZEND_ASSERT(interface_bound_types != NULL && "This must exist at this point");
2223-
if (ce_bound_types_to_inherited_iface == NULL) {
2224-
ALLOC_HASHTABLE(ce_bound_types_to_inherited_iface);
2225-
zend_hash_init(ce_bound_types_to_inherited_iface, inherited_iface->num_generic_parameters, NULL, zend_types_ht_dtor, false /* todo depend on internal or not */);
2226-
zend_hash_add_new_ptr(ce->bound_types, inherited_iface_lc_name, ce_bound_types_to_inherited_iface);
2227-
}
2228-
for (
2229-
uint32_t inherited_iface_generic_param_index = 0;
2230-
inherited_iface_generic_param_index < inherited_iface->num_generic_parameters;
2231-
inherited_iface_generic_param_index++
2232-
) {
2233-
const zend_generic_parameter *inherited_generic_parameter = &inherited_iface->generic_parameters[inherited_iface_generic_param_index];
2234-
const zend_type *iface_bound_type_ptr = zend_hash_index_find_ptr(interface_bound_types, inherited_iface_generic_param_index);
2235-
ZEND_ASSERT(iface_bound_type_ptr != NULL);
2236-
zend_type bound_type;
2237-
if (ZEND_TYPE_IS_ASSOCIATED(*iface_bound_type_ptr)) {
2238-
memcpy(&bound_type, zend_hash_find_ptr(ce_bound_types, ZEND_TYPE_NAME(*iface_bound_type_ptr)), sizeof(zend_type));
2222+
#endif
2223+
return;
2224+
}
2225+
2226+
if (ce->bound_types == NULL) {
2227+
ALLOC_HASHTABLE(ce->bound_types);
2228+
zend_hash_init(ce->bound_types, zend_hash_num_elements(iface_bound_types), NULL, zend_bound_types_ht_dtor, false /* todo depend on internal or not */);
2229+
}
2230+
const HashTable *ce_bound_types_for_direct_iface = zend_hash_find_ptr_lc(ce->bound_types, iface->name);
2231+
2232+
zend_string *lc_inherited_iface_name = NULL;
2233+
const HashTable *interface_bound_types_for_inherited_iface = NULL;
2234+
ZEND_HASH_FOREACH_STR_KEY_PTR(iface_bound_types, lc_inherited_iface_name, interface_bound_types_for_inherited_iface) {
2235+
ZEND_ASSERT(lc_inherited_iface_name != NULL);
2236+
2237+
zend_string *generic_param_name = NULL;
2238+
zend_ulong generic_param_index = 0;
2239+
zend_type *bound_type_ptr = NULL;
2240+
HashTable *ce_bound_types_for_inherited_iface = NULL;
2241+
ALLOC_HASHTABLE(ce_bound_types_for_inherited_iface);
2242+
zend_hash_init(
2243+
ce_bound_types_for_inherited_iface,
2244+
zend_hash_num_elements(interface_bound_types_for_inherited_iface),
2245+
NULL,
2246+
zend_types_ht_dtor,
2247+
false /* TODO depends on internals */
2248+
);
2249+
ZEND_HASH_FOREACH_KEY_PTR(interface_bound_types_for_inherited_iface, generic_param_index, generic_param_name, bound_type_ptr) {
2250+
zend_type bound_type = *bound_type_ptr;
2251+
if (ZEND_TYPE_IS_ASSOCIATED(bound_type)) {
2252+
ZEND_ASSERT(ce_bound_types_for_direct_iface != NULL &&
2253+
"If a bound type is generic then we must have bound types for the current interface");
2254+
// TODO Resolve
2255+
const zend_type *ce_bound_type_ptr = zend_hash_find_ptr(ce_bound_types_for_direct_iface, ZEND_TYPE_NAME(bound_type));
2256+
ZEND_ASSERT(ce_bound_type_ptr != NULL);
2257+
bound_type = *ce_bound_type_ptr;
2258+
}
2259+
2260+
zend_type_copy_ctor(&bound_type, true, false /* TODO Depends on internal or not? */);
2261+
if (generic_param_name) {
2262+
zend_hash_add_mem(ce_bound_types_for_inherited_iface, generic_param_name,
2263+
&bound_type, sizeof(bound_type));
22392264
} else {
2240-
bound_type = *iface_bound_type_ptr;
2265+
zend_hash_index_add_mem(ce_bound_types_for_inherited_iface, generic_param_index,
2266+
&bound_type, sizeof(bound_type));
22412267
}
2242-
/* Deep type copy */
2243-
zend_type_copy_ctor(&bound_type, true, false);
2244-
zend_hash_add_mem(ce_bound_types_to_inherited_iface, inherited_generic_parameter->name,
2245-
&bound_type, sizeof(bound_type));
2246-
}
2247-
zend_string_release_ex(inherited_iface_lc_name, false);
2248-
}
2249-
zend_string_release_ex(iface_lc_name, false);
2268+
} ZEND_HASH_FOREACH_END();
2269+
2270+
// TODO Check we don't already have the bound types for the inherited CE
2271+
//HashTable *
2272+
2273+
zend_hash_add_new_ptr(ce->bound_types, lc_inherited_iface_name, ce_bound_types_for_inherited_iface);
2274+
} ZEND_HASH_FOREACH_END();
22502275
}
22512276

22522277
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
@@ -2334,9 +2359,6 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
23342359
zend_string_release(constraint_type_str);
23352360
return;
23362361
}
2337-
///* Bind our generic type (the key) to the generic iface type */
2338-
//zend_type iface_generic_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(generic_parameter->name), /* allow null */ false, _ZEND_TYPE_ASSOCIATED_BIT);
2339-
//zend_hash_add_mem(bound_types, current_generic_param_name, &iface_generic_type, sizeof(iface_generic_type));
23402362
break;
23412363
}
23422364
} else {
@@ -2354,14 +2376,14 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
23542376
zend_string_release(constraint_type_str);
23552377
return;
23562378
}
2357-
/* Change key from index to generic parameter name */
2358-
/* Deep type copy */
2359-
zend_type bound_type = *bound_type_ptr;
2360-
zend_type_copy_ctor(&bound_type, true, false);
2361-
zend_hash_add_mem(bound_types, generic_parameter->name,
2362-
&bound_type, sizeof(bound_type));
2363-
//zend_hash_index_del(bound_types, i);
23642379
}
2380+
/* Deep type copy */
2381+
zend_type bound_type = *bound_type_ptr;
2382+
zend_type_copy_ctor(&bound_type, true, false);
2383+
zend_hash_add_mem(bound_types, generic_parameter->name,
2384+
&bound_type, sizeof(bound_type));
2385+
///* Should we change the key from index to generic parameter name? */
2386+
//zend_hash_index_del(bound_types, i);
23652387
}
23662388
}
23672389
bind_generic_types_for_inherited_interfaces(ce, iface);

0 commit comments

Comments
 (0)