Skip to content

Commit 6cdc4f5

Browse files
committed
Fix AST and name resolution
1 parent 7fbdc0a commit 6cdc4f5

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
@@ -1570,6 +1570,16 @@ static ZEND_COLD void zend_ast_export_ns_name(smart_str *str, zend_ast *ast, int
15701570
zend_ast_export_ex(str, ast, priority, indent);
15711571
}
15721572

1573+
static ZEND_COLD void zend_ast_export_class_name(smart_str *str, zend_ast *ast, int priority, int indent)
1574+
{
1575+
if (ast->kind == ZEND_AST_CLASS_REF) {
1576+
ZEND_ASSERT(ast->child[1] == NULL && "Generic params not supported yet");
1577+
zend_ast_export_ns_name(str, ast->child[0], priority, indent);
1578+
return;
1579+
}
1580+
zend_ast_export_ex(str, ast, priority, indent);
1581+
}
1582+
15731583
static ZEND_COLD bool zend_ast_valid_var_char(char ch)
15741584
{
15751585
unsigned char c = (unsigned char)ch;
@@ -1690,7 +1700,7 @@ static ZEND_COLD void zend_ast_export_name_list_ex(smart_str *str, zend_ast_list
16901700
if (i != 0) {
16911701
smart_str_appends(str, separator);
16921702
}
1693-
zend_ast_export_name(str, list->child[i], 0, indent);
1703+
zend_ast_export_ns_name(str, list->child[i], 0, indent);
16941704
i++;
16951705
}
16961706
}
@@ -1957,6 +1967,21 @@ static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int in
19571967
zend_ast_export_ns_name(str, ast, 0, indent);
19581968
}
19591969

1970+
static ZEND_COLD void zend_ast_export_generic_arg_list(smart_str *str, const zend_ast_list *list, int indent) {
1971+
// TODO Why cannot I just use
1972+
// zend_ast_export_list(str, list, true, 0, indent);
1973+
// ?
1974+
1975+
uint32_t i = 0;
1976+
while (i < list->children) {
1977+
if (i != 0) {
1978+
smart_str_appends(str, ", ");
1979+
}
1980+
zend_ast_export_type(str, list->child[i], indent);
1981+
i++;
1982+
}
1983+
}
1984+
19601985
static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, zend_ast_list *hook_list, int indent)
19611986
{
19621987
smart_str_appends(str, " {");
@@ -2156,10 +2181,17 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
21562181
}
21572182
smart_str_appends(str, "class ");
21582183
}
2159-
smart_str_appendl(str, ZSTR_VAL(decl->name), ZSTR_LEN(decl->name));
2160-
if (decl->flags & ZEND_ACC_ENUM && decl->child[4]) {
2161-
smart_str_appends(str, ": ");
2162-
zend_ast_export_type(str, decl->child[4], indent);
2184+
smart_str_append(str, decl->name);
2185+
if (decl->child[4]) {
2186+
if (decl->flags & ZEND_ACC_ENUM) {
2187+
smart_str_appends(str, ": ");
2188+
zend_ast_export_type(str, decl->child[4], indent);
2189+
} else {
2190+
ZEND_ASSERT(decl->flags & ZEND_ACC_INTERFACE);
2191+
smart_str_appendc(str, '<');
2192+
zend_ast_export_list(str, zend_ast_get_list(decl->child[4]), true, 0, indent);
2193+
smart_str_appendc(str, '>');
2194+
}
21632195
}
21642196
zend_ast_export_class_no_header(str, decl, indent);
21652197
smart_str_appendc(str, '\n');
@@ -2444,6 +2476,21 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
24442476
smart_str_appends(str, "::");
24452477
zend_ast_export_name(str, ast->child[1], 0, indent);
24462478
break;
2479+
case ZEND_AST_GENERIC_PARAM:
2480+
zend_ast_export_name(str, ast->child[0], 0, indent);
2481+
if (ast->child[1]) {
2482+
smart_str_appendl(str, ZEND_STRL(" : "));
2483+
zend_ast_export_type(str, ast->child[1], indent);
2484+
}
2485+
break;
2486+
case ZEND_AST_CLASS_REF:
2487+
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2488+
if (ast->child[1]) {
2489+
smart_str_appendc(str, '<');
2490+
zend_ast_export_generic_arg_list(str, zend_ast_get_list(ast->child[1]), indent);
2491+
smart_str_appendc(str, '>');
2492+
}
2493+
break;
24472494
case ZEND_AST_CLASS_NAME:
24482495
if (ast->child[0] == NULL) {
24492496
/* The const expr representation stores the fetch type instead. */
@@ -2457,7 +2504,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
24572504
EMPTY_SWITCH_DEFAULT_CASE()
24582505
}
24592506
} else {
2460-
zend_ast_export_ns_name(str, ast->child[0], 0, indent);
2507+
zend_ast_export_class_name(str, ast->child[0], 0, indent);
24612508
}
24622509
smart_str_appends(str, "::class");
24632510
break;
@@ -2725,17 +2772,6 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
27252772
smart_str_appends(str, ": ");
27262773
ast = ast->child[1];
27272774
goto tail_call;
2728-
// TODO Export generic types
2729-
//case ZEND_AST_ASSOCIATED_TYPE:
2730-
// smart_str_appends(str, "type ");
2731-
// zend_ast_export_name(str, ast->child[0], 0, indent);
2732-
// if (ast->child[1]) {
2733-
// smart_str_appends(str, " : ");
2734-
// smart_str_appends(str, " : ");
2735-
// zend_ast_export_type(str, ast->child[1], indent);
2736-
// }
2737-
// smart_str_appendc(str, ';');
2738-
//break;
27392775

27402776
/* 3 child nodes */
27412777
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)