diff --git a/Zend/tests/property_hooks/gh17101.phpt b/Zend/tests/property_hooks/gh17101.phpt new file mode 100644 index 00000000000..3ab53fb75da --- /dev/null +++ b/Zend/tests/property_hooks/gh17101.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-17101 (AST->string does not reproduce constructor property promotion correctly) +--FILE-- + $this->boolVal = 1;} ) {} + }); +} catch (Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +assert(false && new class { + public function __construct(#[Foo] public private(set) bool $boolVal = false { + final set => $this->boolVal = 1; + }) { + } + +}) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 74dd471fb2c..95a67a95b7d 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1761,6 +1761,44 @@ static ZEND_COLD void zend_ast_export_type(smart_str *str, zend_ast *ast, int in zend_ast_export_ns_name(str, ast, 0, indent); } +static ZEND_COLD void zend_ast_export_hook_list(smart_str *str, zend_ast_list *hook_list, int indent) +{ + smart_str_appends(str, " {"); + smart_str_appendc(str, '\n'); + indent++; + zend_ast_export_indent(str, indent); + + for (uint32_t i = 0; i < hook_list->children; i++) { + zend_ast_decl *hook = (zend_ast_decl *)hook_list->child[i]; + zend_ast_export_visibility(str, hook->flags, ZEND_MODIFIER_TARGET_PROPERTY); + if (hook->flags & ZEND_ACC_FINAL) { + smart_str_appends(str, "final "); + } + smart_str_append(str, hook->name); + zend_ast *body = hook->child[2]; + if (body == NULL) { + smart_str_appendc(str, ';'); + } else if (body->kind == ZEND_AST_PROPERTY_HOOK_SHORT_BODY) { + smart_str_appends(str, " => "); + zend_ast_export_ex(str, body->child[0], 0, indent); + smart_str_appendc(str, ';'); + } else { + smart_str_appends(str, " {\n"); + zend_ast_export_stmt(str, body, indent + 1); + zend_ast_export_indent(str, indent); + smart_str_appendc(str, '}'); + } + if (i < (hook_list->children - 1)) { + smart_str_appendc(str, '\n'); + zend_ast_export_indent(str, indent); + } + } + smart_str_appendc(str, '\n'); + indent--; + zend_ast_export_indent(str, indent); + smart_str_appendc(str, '}'); +} + #define BINARY_OP(_op, _p, _pl, _pr) do { \ op = _op; \ p = _p; \ @@ -2406,49 +2444,7 @@ simple_list: } if (ast->child[3]) { - zend_ast_list *hook_list = zend_ast_get_list(ast->child[3]); - - smart_str_appends(str, " {"); - smart_str_appendc(str, '\n'); - indent++; - zend_ast_export_indent(str, indent); - - for (uint32_t i = 0; i < hook_list->children; i++) { - zend_ast_decl *hook = (zend_ast_decl *)hook_list->child[i]; - zend_ast_export_visibility(str, hook->flags, ZEND_MODIFIER_TARGET_PROPERTY); - if (hook->flags & ZEND_ACC_FINAL) { - smart_str_appends(str, "final "); - } - switch (i) { - case ZEND_PROPERTY_HOOK_GET: - smart_str_appends(str, "get"); - break; - case ZEND_PROPERTY_HOOK_SET: - smart_str_appends(str, "set"); - break; - } - zend_ast *body = hook->child[2]; - if (body == NULL) { - smart_str_appendc(str, ';'); - } else if (body->kind == ZEND_AST_PROPERTY_HOOK_SHORT_BODY) { - smart_str_appends(str, " => "); - zend_ast_export_ex(str, body->child[0], 0, indent); - smart_str_appendc(str, ';'); - } else { - smart_str_appends(str, " {\n"); - zend_ast_export_stmt(str, body, indent + 1); - zend_ast_export_indent(str, indent); - smart_str_appendc(str, '}'); - } - if (i < (hook_list->children - 1)) { - smart_str_appendc(str, '\n'); - zend_ast_export_indent(str, indent); - } - } - smart_str_appendc(str, '\n'); - indent--; - zend_ast_export_indent(str, indent); - smart_str_appendc(str, '}'); + zend_ast_export_hook_list(str, zend_ast_get_list(ast->child[3]), indent); } break; case ZEND_AST_CONST_ELEM: @@ -2575,6 +2571,7 @@ simple_list: if (ast->child[3]) { zend_ast_export_attributes(str, ast->child[3], indent, 0); } + zend_ast_export_visibility(str, ast->attr, ZEND_MODIFIER_TARGET_CPP); if (ast->child[0]) { zend_ast_export_type(str, ast->child[0], indent); smart_str_appendc(str, ' '); @@ -2587,7 +2584,14 @@ simple_list: } smart_str_appendc(str, '$'); zend_ast_export_name(str, ast->child[1], 0, indent); - APPEND_DEFAULT_VALUE(2); + if (ast->child[2]) { + smart_str_appends(str, " = "); + zend_ast_export_ex(str, ast->child[2], 0, indent); + } + if (ast->child[5]) { + zend_ast_export_hook_list(str, zend_ast_get_list(ast->child[5]), indent); + } + break; case ZEND_AST_ENUM_CASE: if (ast->child[3]) { zend_ast_export_attributes(str, ast->child[3], indent, 1);