Skip to content

Commit 102c86a

Browse files
committed
move stuff
1 parent e91b2b8 commit 102c86a

6 files changed

+160
-53
lines changed

Zend/tests/type_declarations/abstract_generics/constraints/extended_interface_abstract_generic_types.phpt renamed to Zend/tests/type_declarations/abstract_generics/constraints/extended_interface_abstract_generic_constraint_failure.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
--TEST--
2-
Abstract generic type behaviour in extended interface
2+
Abstract generic type behaviour in extended interface violates type constraint
33
--FILE--
44
<?php
55

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Implicit interface inheritance with different bound types
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2<T> extends I1<T> {
11+
public function bar(int $o, T $param): T;
12+
}
13+
14+
class C implements I2<float>, I1<string> {
15+
public function foo(float $param): float {}
16+
public function bar(int $o, float $param): float {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Bound type float is not a subtype of the constraint type string|int of generic type T of interface I in %s on line %d
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Implicit interface inheritance missing bound types
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2<T> extends I1<T> {
11+
public function bar(int $o, T $param): T;
12+
}
13+
14+
class C implements I2<float>, I1 {
15+
public function foo(float $param): float {}
16+
public function bar(int $o, float $param): float {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Bound type float is not a subtype of the constraint type string|int of generic type T of interface I in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface
3+
--FILE--
4+
<?php
5+
6+
interface I1<T1> {
7+
public function foo(T1 $param): T1;
8+
}
9+
10+
interface I2<T2> extends I1<T2> {
11+
public function bar(int $o, T2 $param): T2;
12+
}
13+
14+
interface I3<T3> extends I2<T3> {
15+
public function foobar(T3 $a, float $b): float;
16+
}
17+
18+
class C implements I3<string> {
19+
public function foo(string $param): string {}
20+
public function bar(int $o, string $param): string {}
21+
public function foobar(string $a, float $b): float {}
22+
}
23+
24+
?>
25+
DONE
26+
--EXPECT--
27+
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
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Abstract generic type behaviour in extended interface
3+
--FILE--
4+
<?php
5+
6+
interface I1<T1> {
7+
public function foo(T1 $param): T1;
8+
}
9+
10+
interface I2<T2> extends I1<T2> {
11+
public function bar(int $o, T2 $param): T2;
12+
}
13+
14+
interface I3 extends I2<string> {
15+
public function foobar(string $a, float $b): float;
16+
}
17+
18+
class C implements I3 {
19+
public function foo(string $param): string {}
20+
public function bar(int $o, string $param): string {}
21+
public function foobar(string $a, float $b): float {}
22+
}
23+
24+
?>
25+
DONE
26+
--EXPECT--
27+
DONE

Zend/zend_inheritance.c

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,57 +1640,6 @@ static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry
16401640
}
16411641
/* }}} */
16421642

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-
16941643
static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
16951644
{
16961645
/* expects interface to be contained in ce's interface list already */
@@ -2249,6 +2198,57 @@ static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c,
22492198
}
22502199
/* }}} */
22512200

2201+
// TODO Merge with the one in zend_compile
2202+
static void zend_types_ht_dtor(zval *ptr) {
2203+
zend_type *type = Z_PTR_P(ptr);
2204+
// TODO Figure out persistency?
2205+
zend_type_release(*type, false);
2206+
efree(type);
2207+
}
2208+
2209+
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+
zend_class_entry *entry = iface->interfaces[i];
2214+
/* Bind generic types */
2215+
/* We need to propagate the bound generic parameters to the inherited interfaces */
2216+
if (entry->num_generic_parameters == 0) {
2217+
continue;
2218+
}
2219+
zend_string *inherited_iface_lc_name = zend_string_tolower(entry->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, entry->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 < entry->num_generic_parameters;
2231+
inherited_iface_generic_param_index++
2232+
) {
2233+
const zend_generic_parameter *inherited_generic_parameter = &entry->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));
2239+
} else {
2240+
bound_type = *iface_bound_type_ptr;
2241+
}
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);
2250+
}
2251+
22522252
static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
22532253
{
22542254
zend_function *func;
@@ -2334,6 +2334,9 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
23342334
zend_string_release(constraint_type_str);
23352335
return;
23362336
}
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));
23372340
break;
23382341
}
23392342
} else {
@@ -2361,7 +2364,7 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
23612364
}
23622365
}
23632366
}
2364-
interface_bind_generic_types_for_interfaces(ce, iface);
2367+
bind_generic_types_for_inherited_interfaces(ce, iface);
23652368
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
23662369
do_inherit_iface_constant(key, c, ce, iface);
23672370
} ZEND_HASH_FOREACH_END();

0 commit comments

Comments
 (0)