Skip to content

Commit 7751731

Browse files
committed
Associate type to CE and minimal duplicate check
1 parent 2336ef4 commit 7751731

File tree

5 files changed

+52
-5
lines changed

5 files changed

+52
-5
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Multiple associated types
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type K;
8+
type V;
9+
public function set(K $key, V $value): void;
10+
public function get(K $key): V;
11+
}
12+
13+
class C implements I {
14+
public function set(int $key, string $value): void {}
15+
public function get(int $key): string {}
16+
}
17+
18+
?>
19+
--EXPECTF--
20+
Fatal error: Declaration of C::set(int $key, string $value): void must be compatible with I::set(K $key, V $value): void in %s on line %d

Zend/tests/type_declarations/associated/repeated_associated_type.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
--TEST--
2-
Associated types basic
2+
Repeated associated type
33
--FILE--
44
<?php
55

66
interface I {
7+
type T;
78
type T;
89
public function foo(T $param): T;
910
}
@@ -14,4 +15,4 @@ class C implements I {
1415

1516
?>
1617
--EXPECTF--
17-
Parse error: syntax error, unexpected token "type", expecting "function" in %s on line %d
18+
Fatal error: Cannot have two associated types with the same name "T" in %s on line %d

Zend/zend.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ struct _zend_class_entry {
218218
zend_trait_precedence **trait_precedences;
219219
HashTable *attributes;
220220

221+
/* Only for interfaces */
222+
HashTable *associated_types;
223+
221224
uint32_t enum_backing_type;
222225
HashTable *backed_enum_table;
223226

Zend/zend_compile.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,6 +2072,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_hand
20722072
ce->default_static_members_count = 0;
20732073
ce->properties_info_table = NULL;
20742074
ce->attributes = NULL;
2075+
ce->associated_types = NULL;
20752076
ce->enum_backing_type = IS_UNDEF;
20762077
ce->backed_enum_table = NULL;
20772078

@@ -9011,18 +9012,33 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90119012
}
90129013
/* }}} */
90139014

9015+
9016+
90149017
static void zend_compile_associated_type(zend_ast *ast) {
90159018
zend_class_entry *ce = CG(active_class_entry);
9019+
HashTable *associated_types = ce->associated_types;
9020+
zend_ast *name_ast = ast->child[0];
9021+
zend_string *name = zend_ast_get_str(name_ast);
90169022

90179023
if ((ce->ce_flags & ZEND_ACC_INTERFACE) == 0) {
90189024
zend_error_noreturn(E_COMPILE_ERROR,
90199025
"Cannot use associated types outside of interfaces, used in %s", ZSTR_VAL(ce->name));
90209026
}
90219027

9022-
zend_ast *name_ast = ast->child[0];
9023-
zend_string *name = zend_ast_get_str(name_ast);
90249028
ZEND_ASSERT(name != NULL);
9025-
// TODO add associated type to CE
9029+
bool persistent = ce->type == ZEND_INTERNAL_CLASS;
9030+
if (associated_types == NULL) {
9031+
ce->associated_types = pemalloc(sizeof(HashTable), persistent);
9032+
zend_hash_init(ce->associated_types, 8, NULL, NULL, persistent);
9033+
associated_types = ce->associated_types;
9034+
}
9035+
if (zend_hash_exists(associated_types, name)) {
9036+
zend_error_noreturn(E_COMPILE_ERROR,
9037+
"Cannot have two associated types with the same name \"%s\"", ZSTR_VAL(name));
9038+
}
9039+
zval tmp;
9040+
ZVAL_UNDEF(&tmp);
9041+
zend_hash_add_new(associated_types, name, &tmp);
90269042
}
90279043

90289044
static void zend_compile_implements(zend_ast *ast) /* {{{ */

Zend/zend_opcode.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,10 @@ ZEND_API void destroy_zend_class(zval *zv)
351351
zend_hash_release(ce->attributes);
352352
}
353353

354+
if (ce->associated_types) {
355+
zend_hash_release(ce->associated_types);
356+
}
357+
354358
if (ce->num_interfaces > 0 && !(ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES)) {
355359
uint32_t i;
356360

@@ -527,6 +531,9 @@ ZEND_API void destroy_zend_class(zval *zv)
527531
if (ce->attributes) {
528532
zend_hash_release(ce->attributes);
529533
}
534+
if (ce->associated_types) {
535+
zend_hash_release(ce->associated_types);
536+
}
530537
free(ce);
531538
break;
532539
}

0 commit comments

Comments
 (0)