Skip to content

Commit 83c392d

Browse files
committed
Do some fixes about implicit and explicit interface implementations
1 parent 6f53c99 commit 83c392d

7 files changed

+119
-6
lines changed

Zend/tests/type_declarations/abstract_generics/constraints/implicit_interface_different_bound_types.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,4 @@ class C implements I2<float>, I1<string> {
1818

1919
?>
2020
--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
21+
Fatal error: Bound types for implicitly and explicitly implemented interfaces must match in %s on line %d
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Implicit interface inheritance with different bound types 2
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 I1<string>, I2<float> {
15+
public function foo(string $param): string {}
16+
public function bar(int $o, float $param): float {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Bound types for implicitly and explicitly implemented interfaces must match in %s on line %d

Zend/tests/type_declarations/abstract_generics/constraints/implicit_interface_no_bound_types.phpt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
--TEST--
22
Implicit interface inheritance missing bound types
3+
--XFAIL--
4+
Wrong number of missing params
35
--FILE--
46
<?php
57

@@ -18,4 +20,4 @@ class C implements I2<float>, I1 {
1820

1921
?>
2022
--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
23+
Fatal error: Cannot implement I1 as the number of generic arguments specified (0) does not match the number of generic parameters declared on the interface (1) 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 2
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 I1, I2<float> {
15+
public function foo(float $param): float {}
16+
public function bar(int $o, float $param): float {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Cannot implement I1 as it has generic parameters which are not specified in %s on line %d
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
Implicit interface inheritance with same bound types
3+
--XFAIL--
4+
This emits an error when it shouldn't
5+
--FILE--
6+
<?php
7+
8+
interface I1<T> {
9+
public function foo(T $param): T;
10+
}
11+
12+
interface I2<T> extends I1<T> {
13+
public function bar(int $o, T $param): T;
14+
}
15+
16+
class C implements I2<string>, I1<string> {
17+
public function foo(string $param): string {}
18+
public function bar(int $o, string $param): string {}
19+
}
20+
21+
?>
22+
DONE
23+
--EXPECT--
24+
DONE
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Implicit interface inheritance with same bound types 2
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 I1<string>, I2<string> {
15+
public function foo(string $param): string {}
16+
public function bar(int $o, string $param): string {}
17+
}
18+
19+
?>
20+
DONE
21+
--EXPECT--
22+
DONE

Zend/zend_inheritance.c

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,7 +2251,6 @@ ZEND_ATTRIBUTE_NONNULL static void bind_generic_types_for_inherited_interfaces(z
22512251
if (ZEND_TYPE_IS_ASSOCIATED(bound_type)) {
22522252
ZEND_ASSERT(ce_bound_types_for_direct_iface != NULL &&
22532253
"If a bound type is generic then we must have bound types for the current interface");
2254-
// TODO Resolve
22552254
const zend_type *ce_bound_type_ptr = zend_hash_find_ptr(ce_bound_types_for_direct_iface, ZEND_TYPE_NAME(bound_type));
22562255
ZEND_ASSERT(ce_bound_type_ptr != NULL);
22572256
bound_type = *ce_bound_type_ptr;
@@ -2267,9 +2266,32 @@ ZEND_ATTRIBUTE_NONNULL static void bind_generic_types_for_inherited_interfaces(z
22672266
}
22682267
} ZEND_HASH_FOREACH_END();
22692268

2270-
// TODO Check we don't already have the bound types for the inherited CE
2271-
//HashTable *
2272-
2269+
const HashTable *existing_bound_types_for_inherited_iface = zend_hash_find_ptr(ce->bound_types, lc_inherited_iface_name);
2270+
if (EXPECTED(existing_bound_types_for_inherited_iface == NULL)) {
2271+
} else {
2272+
zend_ulong idx;
2273+
zend_string *bound_name;
2274+
const zend_type *ptr;
2275+
ZEND_HASH_FOREACH_KEY_PTR(existing_bound_types_for_inherited_iface, idx, bound_name, ptr) {
2276+
if (bound_name != NULL) {
2277+
continue;
2278+
}
2279+
const zend_type t1 = *ptr;
2280+
const zend_type *ptr2 = zend_hash_index_find_ptr(ce_bound_types_for_inherited_iface, idx);
2281+
ZEND_ASSERT(ptr2 != NULL);
2282+
const zend_type t2 = *ptr2;
2283+
if (
2284+
ZEND_TYPE_FULL_MASK(t1) != ZEND_TYPE_FULL_MASK(t2)
2285+
|| (ZEND_TYPE_HAS_NAME(t1) && !zend_string_equals(ZEND_TYPE_NAME(t1), ZEND_TYPE_NAME(t2)))
2286+
// || ZEND_TYPE_HAS_LIST(t1) && TODO Check list types are equal
2287+
) {
2288+
// TODO Improve this error message
2289+
zend_error_noreturn(E_COMPILE_ERROR, "Bound types for implicitly and explicitly implemented interfaces must match");
2290+
}
2291+
} ZEND_HASH_FOREACH_END();
2292+
/* Remove current ones as they may be incomplete without the type name binding */
2293+
zend_hash_del(ce->bound_types, lc_inherited_iface_name);
2294+
}
22732295
zend_hash_add_new_ptr(ce->bound_types, lc_inherited_iface_name, ce_bound_types_for_inherited_iface);
22742296
} ZEND_HASH_FOREACH_END();
22752297
}
@@ -2310,6 +2332,7 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
23102332
}
23112333
const uint32_t num_bound_types = zend_hash_num_elements(bound_types);
23122334
if (UNEXPECTED(num_bound_types != iface->num_generic_parameters)) {
2335+
// TODO Need to handle implicit inherited interfaces
23132336
zend_error_noreturn(E_COMPILE_ERROR,
23142337
"Cannot implement %s as the number of generic arguments specified (%" PRIu32 ") does not match the number of generic parameters declared on the interface (%" PRIu32 ")",
23152338
ZSTR_VAL(iface->name),

0 commit comments

Comments
 (0)