Skip to content

Commit a95179e

Browse files
committed
Support minimal compilation of associated type
1 parent 5faae7d commit a95179e

8 files changed

+73
-1
lines changed

Zend/tests/type_declarations/associated/associated_001.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ class C implements I {
1414

1515
?>
1616
--EXPECTF--
17-
Parse error: syntax error, unexpected token "type", expecting "function" in %s on line %d
17+
Fatal error: Declaration of C::foo(string $param): string must be compatible with I::foo(T $param): T in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated types in class is invalid
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
type T;
8+
public function foo(T $param): T;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Cannot use associated types outside of interfaces, used in C in %s on line %d
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Associated types in trait is invalid
3+
--FILE--
4+
<?php
5+
6+
trait C {
7+
type T;
8+
public function foo(T $param): T;
9+
}
10+
11+
?>
12+
--EXPECTF--
13+
Fatal error: Cannot use associated types outside of interfaces, used in C in %s on line %d
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Associated types basic
3+
--FILE--
4+
<?php
5+
6+
interface I {
7+
type T;
8+
public function foo(T $param): T;
9+
}
10+
11+
class C implements I {
12+
public function foo(string $param): string {}
13+
}
14+
15+
?>
16+
--EXPECTF--
17+
Parse error: syntax error, unexpected token "type", expecting "function" in %s on line %d

Zend/zend_ast.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,6 +2342,10 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
23422342
APPEND_NODE_1("break");
23432343
case ZEND_AST_CONTINUE:
23442344
APPEND_NODE_1("continue");
2345+
case ZEND_AST_ASSOCIATED_TYPE:
2346+
smart_str_appends(str, "type ");
2347+
zend_ast_export_name(str, ast->child[0], 0, indent);
2348+
break;
23452349

23462350
/* 2 child nodes */
23472351
case ZEND_AST_DIM:

Zend/zend_ast.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ enum _zend_ast_kind {
9999
ZEND_AST_POST_DEC,
100100
ZEND_AST_YIELD_FROM,
101101
ZEND_AST_CLASS_NAME,
102+
ZEND_AST_ASSOCIATED_TYPE,
102103

103104
ZEND_AST_GLOBAL,
104105
ZEND_AST_UNSET,

Zend/zend_compile.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9020,6 +9020,20 @@ static void zend_compile_use_trait(zend_ast *ast) /* {{{ */
90209020
}
90219021
/* }}} */
90229022

9023+
static void zend_compile_associated_type(zend_ast *ast) {
9024+
zend_class_entry *ce = CG(active_class_entry);
9025+
9026+
if ((ce->ce_flags & ZEND_ACC_INTERFACE) == 0) {
9027+
zend_error_noreturn(E_COMPILE_ERROR,
9028+
"Cannot use associated types outside of interfaces, used in %s", ZSTR_VAL(ce->name));
9029+
}
9030+
9031+
zend_ast *name_ast = ast->child[0];
9032+
zend_string *name = zend_ast_get_str(name_ast);
9033+
ZEND_ASSERT(name != NULL);
9034+
// TODO add associated type to CE
9035+
}
9036+
90239037
static void zend_compile_implements(zend_ast *ast) /* {{{ */
90249038
{
90259039
zend_ast_list *list = zend_ast_get_list(ast);
@@ -11586,6 +11600,9 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1158611600
case ZEND_AST_USE_TRAIT:
1158711601
zend_compile_use_trait(ast);
1158811602
break;
11603+
case ZEND_AST_ASSOCIATED_TYPE:
11604+
zend_compile_associated_type(ast);
11605+
break;
1158911606
case ZEND_AST_CLASS:
1159011607
zend_compile_class_decl(NULL, ast, 0);
1159111608
break;

Zend/zend_language_parser.y

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
287287
%type <ast> function_name non_empty_member_modifiers
288288
%type <ast> property_hook property_hook_list optional_property_hook_list hooked_property property_hook_body
289289
%type <ast> optional_parameter_list
290+
%type <ast> associated_type
290291

291292
%type <num> returns_ref function fn is_reference is_variadic property_modifiers property_hook_modifiers
292293
%type <num> method_modifiers class_const_modifiers member_modifier optional_cpp_modifiers
@@ -662,6 +663,11 @@ enum_case_expr:
662663
| '=' expr { $$ = $2; }
663664
;
664665

666+
associated_type:
667+
T_TYPE name ';'
668+
{ $$ = zend_ast_create(ZEND_AST_ASSOCIATED_TYPE, $2); }
669+
;
670+
665671
extends_from:
666672
%empty { $$ = NULL; }
667673
| T_EXTENDS class_name { $$ = $2; }
@@ -963,6 +969,7 @@ attributed_class_statement:
963969
{ $$ = zend_ast_create_decl(ZEND_AST_METHOD, $3 | $1 | $12, $2, $5,
964970
zend_ast_get_str($4), $7, NULL, $11, $9, NULL); CG(extra_fn_flags) = $10; }
965971
| enum_case { $$ = $1; }
972+
| associated_type { $$ = $1; }
966973
;
967974

968975
class_statement:

0 commit comments

Comments
 (0)