Skip to content

Commit 3a8b3d2

Browse files
committed
Fix AST and name resolution
1 parent 24bcdee commit 3a8b3d2

File tree

3 files changed

+112
-18
lines changed

3 files changed

+112
-18
lines changed

Zend/zend_ast.c

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1569,6 +1569,16 @@ static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int
15691569
zend_ast_export_ex(str, ast, priority, indent);
15701570
}
15711571

1572+
static ZEND_COLD void zend_ast_export_class_name(smart_str *str, zend_ast *ast, int priority, int indent)
1573+
{
1574+
if (ast->kind == ZEND_AST_CLASS_REF) {
1575+
ZEND_ASSERT(ast->child[1] == NULL && "Generic params not supported yet");
1576+
zend_ast_export_ns_name(str, ast->child[0], priority, indent);
1577+
return;
1578+
}
1579+
zend_ast_export_ex(str, ast, priority, indent);
1580+
}
1581+
15721582
static ZEND_COLD bool zend_ast_valid_var_char(char ch)
15731583
{
15741584
unsigned char c = (unsigned char)ch;
@@ -1689,7 +1699,7 @@ static ZEND_COLD void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list
16891699
if (i != 0) {
16901700
smart_str_appends(str, separator);
16911701
}
1692-
zend_ast_export_name(str, list->child[i], 0, indent);
1702+
zend_ast_export_ns_name(str, list->child[i], 0, indent);
16931703
i++;
16941704
}
16951705
}
@@ -1956,6 +1966,21 @@ static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int in
19561966
zend_ast_export_ns_name(str, ast, 0, indent);
19571967
}
19581968

1969+
static ZEND_COLD void zend_ast_export_generic_arg_list(smart_str *str, const zend_ast_list *list, int indent) {
1970+
// TODO Why cannot I just use
1971+
// zend_ast_export_list(str, list, true, 0, indent);
1972+
// ?
1973+
1974+
uint32_t i = 0;
1975+
while (i < list->children) {
1976+
if (i != 0) {
1977+
smart_str_appends(str, ", ");
1978+
}
1979+
zend_ast_export_type(str, list->child[i], indent);
1980+
i++;
1981+
}
1982+
}
1983+
19591984
static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, zend_ast_list *hook_list, int indent)
19601985
{
19611986
smart_str_appends(str, " {");
@@ -2155,10 +2180,17 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
21552180
}
21562181
smart_str_appends(str, "class ");
21572182
}
2158-
smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
2159-
if (decl->flags & ZEND_ACC_ENUM && decl->child[4]) {
2160-
smart_str_appends(str, ": ");
2161-
zend_ast_export_type(str, decl->child[4], indent);
2183+
smart_str_append(str, decl->name);
2184+
if (decl->child[4]) {
2185+
if (decl->flags & ZEND_ACC_ENUM) {
2186+
smart_str_appends(str, ": ");
2187+
zend_ast_export_type(str, decl->child[4], indent);
2188+
} else {
2189+
ZEND_ASSERT(decl->flags & ZEND_ACC_INTERFACE);
2190+
smart_str_appendc(str, '<');
2191+
zend_ast_export_list(str, zend_ast_get_list(decl->child[4]), true, 0, indent);
2192+
smart_str_appendc(str, '>');
2193+
}
21622194
}
21632195
zend_ast_export_class_no_header(str, decl, indent);
21642196
smart_str_appendc(str, '\n');
@@ -2443,6 +2475,21 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
24432475
smart_str_appends(str, "::");
24442476
zend_ast_export_name(str, ast->child[1], 0, indent);
24452477
break;
2478+
case ZEND_AST_GENERIC_PARAM:
2479+
zend_ast_export_name(str, ast->child[0], 0, indent);
2480+
if (ast->child[1]) {
2481+
smart_str_appendl(str, ZEND_STRL(" : "));
2482+
zend_ast_export_type(str, ast->child[1], indent);
2483+
}
2484+
break;
2485+
case ZEND_AST_CLASS_REF:
2486+
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2487+
if (ast->child[1]) {
2488+
smart_str_appendc(str, '<');
2489+
zend_ast_export_generic_arg_list(str, zend_ast_get_list(ast->child[1]), indent);
2490+
smart_str_appendc(str, '>');
2491+
}
2492+
break;
24462493
case ZEND_AST_CLASS_NAME:
24472494
if (ast->child[0] == NULL) {
24482495
/* The const expr representation stores the fetch type instead. */
@@ -2456,7 +2503,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
24562503
EMPTY_SWITCH_DEFAULT_CASE()
24572504
}
24582505
} else {
2459-
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2506+
zend_ast_export_class_name(str, ast->child[0], 0, indent);
24602507
}
24612508
smart_str_appends(str, "::class");
24622509
break;
@@ -2724,17 +2771,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
27242771
smart_str_appends(str, ": ");
27252772
ast = ast->child[1];
27262773
goto tail_call;
2727-
// TODO Export generic types
2728-
//case ZEND_AST_ASSOCIATED_TYPE:
2729-
// smart_str_appends(str, "type ");
2730-
// zend_ast_export_name(str, ast->child[0], 0, indent);
2731-
// if (ast->child[1]) {
2732-
// smart_str_appends(str, " : ");
2733-
// smart_str_appends(str, " : ");
2734-
// zend_ast_export_type(str, ast->child[1], indent);
2735-
// }
2736-
// smart_str_appendc(str, ';');
2737-
//break;
27382774

27392775
/* 3 child nodes */
27402776
case ZEND_AST_METHOD_CALL:

Zend/zend_compile.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9120,7 +9120,7 @@ static zend_string *zend_generate_anon_class_name(zend_ast_decl *decl)
91209120
prefix = zend_resolve_const_class_name_reference(decl->child[0], "class name");
91219121
} else if (decl->child[1]) {
91229122
zend_ast_list *list = zend_ast_get_list(decl->child[1]);
9123-
prefix = zend_resolve_const_class_name_reference(list->child[0], "interface name");
9123+
prefix = zend_resolve_const_class_name_reference_with_generics(list->child[0], "interface name");
91249124
}
91259125

91269126
zend_string *result = zend_strpprintf(0, "%s@anonymous%c%s:%" PRIu32 "$%" PRIx32,
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
AST can be recreated (interface with generic types)
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
namespace {
9+
interface MyInterface1<T1 : string|Stringable|int, T2> {
10+
public function bar(T1 $v): T2;
11+
}
12+
}
13+
14+
namespace Foo {
15+
interface MyInterface2<S : string|\Stringable|int> extends \MyInterface1<S, S> {
16+
public function foobar(S $v): int;
17+
}
18+
19+
class MyClass implements MyInterface2<string> {
20+
public function bar(string $v): string {}
21+
public function foobar(string $v): int {}
22+
}
23+
}
24+
25+
namespace {
26+
echo zend_test_compile_to_ast( file_get_contents( __FILE__ ) );
27+
}
28+
29+
?>
30+
--EXPECT--
31+
namespace {
32+
interface MyInterface1<T1 : string|Stringable|int, T2> {
33+
public function bar(T1 $v): T2;
34+
35+
}
36+
37+
}
38+
39+
namespace Foo {
40+
interface MyInterface2<S : string|\Stringable|int> implements \MyInterface1<S, S> {
41+
public function foobar(S $v): int;
42+
43+
}
44+
45+
class MyClass implements MyInterface2<string> {
46+
public function bar(string $v): string {
47+
}
48+
49+
public function foobar(string $v): int {
50+
}
51+
52+
}
53+
54+
}
55+
56+
namespace {
57+
echo zend_test_compile_to_ast(file_get_contents(__FILE__));
58+
}

0 commit comments

Comments
 (0)