Skip to content

Commit 891f24d

Browse files
committed
Fix some implicit bound type issues
1 parent 229fcc9 commit 891f24d

11 files changed

+109
-20
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
--TEST--
2+
Implicit interface inheritance with different bound types 3
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2 extends I1<float> {
11+
public function bar(int $o, float $param): float;
12+
}
13+
14+
class C implements I2, 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 T for interface I1 implemented explicitly in C with type string must match the implicitly bound type float from interface I2 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 4
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2 extends I1<float> {
11+
public function bar(int $o, float $param): float;
12+
}
13+
14+
class C implements I1<string>, I2 {
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 type T for interface I1 implemented explicitly in C with type string must match the implicitly bound type float from interface I2 in %s on line %d

Zend/tests/type_declarations/abstract_generics/constraints/implicit_interface_no_bound_types.phpt renamed to Zend/tests/type_declarations/abstract_generics/bound_types/implicit_interface_no_bound_types.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
--TEST--
22
Implicit interface inheritance missing bound types
3-
--XFAIL--
4-
Wrong number of missing params
53
--FILE--
64
<?php
75

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
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2 extends I1<string> {
11+
public function bar(int $o, string $param): string;
12+
}
13+
14+
class C implements I1, I2 {
15+
public function foo(string $param): string {}
16+
public function bar(int $o, string $param): string {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Interface I1 expects 1 generic parameters, 0 given 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 4
3+
--FILE--
4+
<?php
5+
6+
interface I1<T> {
7+
public function foo(T $param): T;
8+
}
9+
10+
interface I2 extends I1<string> {
11+
public function bar(int $o, string $param): string;
12+
}
13+
14+
class C implements I2, I1 {
15+
public function foo(string $param): string {}
16+
public function bar(int $o, string $param): string {}
17+
}
18+
19+
?>
20+
--EXPECTF--
21+
Fatal error: Interface I1 expects 1 generic parameters, 0 given in %s on line %d

Zend/zend_inheritance.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1738,6 +1738,15 @@ static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry
17381738
do_implement_interface_ex(ce, iface, iface);
17391739
}
17401740

1741+
static ZEND_COLD void emit_incompatible_generic_arg_count_error(const zend_class_entry *iface, uint32_t given_args) {
1742+
zend_error_noreturn(E_COMPILE_ERROR,
1743+
"Interface %s expects %" PRIu32 " generic parameters, %" PRIu32 " given",
1744+
ZSTR_VAL(iface->name),
1745+
iface->num_generic_parameters,
1746+
given_args
1747+
);
1748+
}
1749+
17411750
static void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
17421751
{
17431752
/* expects interface to be contained in ce's interface list already */
@@ -1756,7 +1765,19 @@ static void zend_do_inherit_interfaces(zend_class_entry *ce, zend_class_entry *i
17561765
zend_class_entry *entry = iface->interfaces[if_num];
17571766
for (i = 0; i < ce_num; i++) {
17581767
if (ce->interfaces[i] == entry) {
1759-
// TODO Check bound generic types match? Or is this done before?
1768+
if (entry->num_generic_parameters) {
1769+
if (UNEXPECTED(ce->bound_types == NULL)) {
1770+
emit_incompatible_generic_arg_count_error(entry, 0);
1771+
}
1772+
const HashTable *bound_types = zend_hash_find_ptr_lc(ce->bound_types, entry->name);
1773+
if (UNEXPECTED(bound_types == NULL)) {
1774+
emit_incompatible_generic_arg_count_error(entry, 0);
1775+
}
1776+
const uint32_t num_bound_types = zend_hash_num_elements(bound_types);
1777+
if (UNEXPECTED(num_bound_types != entry->num_generic_parameters)) {
1778+
emit_incompatible_generic_arg_count_error(entry, num_bound_types);
1779+
}
1780+
}
17601781
break;
17611782
}
17621783
}
@@ -2429,29 +2450,15 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
24292450

24302451
if (iface->num_generic_parameters > 0) {
24312452
if (UNEXPECTED(ce->bound_types == NULL)) {
2432-
zend_error_noreturn(E_COMPILE_ERROR,
2433-
"Interface %s expects %" PRIu32 " generic parameters, 0 given",
2434-
ZSTR_VAL(iface->name),
2435-
iface->num_generic_parameters
2436-
);
2453+
emit_incompatible_generic_arg_count_error(iface, 0);
24372454
}
24382455
HashTable *bound_types = zend_hash_find_ptr_lc(ce->bound_types, iface->name);
24392456
if (UNEXPECTED(bound_types == NULL)) {
2440-
zend_error_noreturn(E_COMPILE_ERROR,
2441-
"Interface %s expects %" PRIu32 " generic parameters, 0 given",
2442-
ZSTR_VAL(iface->name),
2443-
iface->num_generic_parameters
2444-
);
2457+
emit_incompatible_generic_arg_count_error(iface, 0);
24452458
}
24462459
const uint32_t num_bound_types = zend_hash_num_elements(bound_types);
24472460
if (UNEXPECTED(num_bound_types != iface->num_generic_parameters)) {
2448-
// TODO Need to handle implicit inherited interfaces
2449-
zend_error_noreturn(E_COMPILE_ERROR,
2450-
"Interface %s expects %" PRIu32 " generic parameters, %" PRIu32 " given",
2451-
ZSTR_VAL(iface->name),
2452-
iface->num_generic_parameters,
2453-
num_bound_types
2454-
);
2461+
emit_incompatible_generic_arg_count_error(iface, num_bound_types);
24552462
}
24562463
for (uint32_t i = 0; i < num_bound_types; i++) {
24572464
const zend_generic_parameter *generic_parameter = &iface->generic_parameters[i];

0 commit comments

Comments
 (0)