Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit cc039c9

Browse files
committed
Add basic support for extending interfaces with associated type
1 parent e9c28b1 commit cc039c9

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--TEST--
2+
Associated type behaviour in extended interface
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T : int|string;
8+
public function foo(T $param): T;
9+
}
10+
11+
interface I2 extends I {
12+
type T;
13+
public function bar(int $o, T $param): T;
14+
}
15+
16+
class C implements I2 {
17+
public function foo(string $param): string {}
18+
public function bar(int $o, float $param): float {}
19+
}
20+
21+
?>
22+
--EXPECTF--
23+
Fatal error: Cannot redeclare associated type T in interface I2 inherited from interface I in %s on line %d
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Associated type behaviour in extended interface
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T : int|string|(Traversable&Countable);
8+
public function foo(T $param): T;
9+
}
10+
11+
interface I2 extends I {
12+
public function bar(int $o, T $param): T;
13+
}
14+
15+
class C implements I2 {
16+
public function foo(string $param): string {}
17+
public function bar(int $o, float $param): float {}
18+
}
19+
20+
?>
21+
--EXPECTF--
22+
Fatal error: Declaration of C::bar(int $o, float $param): float must be compatible with I2::bar(int $o, T $param): T in %s on line %d
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Associated type behaviour in extended interface
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T : int|string|(Traversable&Countable);
8+
public function foo(T $param): T;
9+
}
10+
11+
interface I2 extends I {
12+
type T2 : float|bool|stdClass;
13+
public function bar(T2 $o, T $param): T2;
14+
}
15+
16+
class C implements I2 {
17+
public function foo(string $param): string {}
18+
public function bar(float $o, string $param): float {}
19+
}
20+
21+
// TODO: Ideally error message would be:
22+
//Fatal error: Declaration of C::bar(float $o, string $param): float must be compatible with I2::bar(T2<stdClass|float|bool> $o, T<(Traversable&Countable)|int|string> $param): T2<stdClass|float|bool> in %s on line %d
23+
//Improve zend_append_type_hint()?
24+
?>
25+
--EXPECTF--
26+
Fatal error: Declaration of C::bar(float $o, string $param): float must be compatible with I2::bar(T2<stdClass|float|bool> $o, T $param): T2<stdClass|float|bool> in %s on line %d

‎Zend/zend_inheritance.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2232,8 +2232,31 @@ static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *
22322232
}
22332233

22342234
if (iface->associated_types) {
2235+
const uint32_t num_associated_types = zend_hash_num_elements(iface->associated_types);
2236+
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2237+
const bool persistent = ce->type == ZEND_INTERNAL_CLASS;
2238+
if (ce->associated_types) {
2239+
zend_string *associated_type_name;
2240+
zend_type *associated_type_ptr;
2241+
ZEND_HASH_FOREACH_STR_KEY_PTR(iface->associated_types, associated_type_name, associated_type_ptr) {
2242+
if (zend_hash_exists(ce->associated_types, associated_type_name)) {
2243+
zend_error_noreturn(E_ERROR,
2244+
"Cannot redeclare associated type %s in interface %s inherited from interface %s",
2245+
ZSTR_VAL(associated_type_name), ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
2246+
}
2247+
/* Deep copy the type information */
2248+
zend_type_copy_ctor(associated_type_ptr, /* use_arena */ !persistent, /* persistent */ persistent);
2249+
zend_hash_add_new_mem(ce->associated_types, associated_type_name, associated_type_ptr, sizeof(*associated_type_ptr));
2250+
} ZEND_HASH_FOREACH_END();
2251+
} else {
2252+
ce->associated_types = pemalloc(sizeof(HashTable), persistent);
2253+
zend_hash_init(ce->associated_types, num_associated_types, NULL, NULL, false);
2254+
zend_hash_copy(ce->associated_types, iface->associated_types, NULL);
2255+
}
2256+
return;
2257+
}
22352258
HashTable *ht = emalloc(sizeof(HashTable));
2236-
zend_hash_init(ht, zend_hash_num_elements(iface->associated_types), NULL, NULL, false);
2259+
zend_hash_init(ht, num_associated_types, NULL, NULL, false);
22372260
CG(bound_associated_types) = ht;
22382261
}
22392262
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /