Correctly handle multiple constants in typed declaration

While here also fix AST printing support.
This commit is contained in:
Nikita Popov 2023-05-20 18:20:13 +02:00 committed by Nikita Popov
parent 03b163b2b3
commit c230aa9be3
6 changed files with 52 additions and 16 deletions

View file

@ -0,0 +1,18 @@
--TEST--
AST printing support for typed constants
--FILE--
<?php
try {
assert(false && new class {
public const int X = 1;
});
} catch (AssertionError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
assert(false && new class {
public const int X = 1;
})

View file

@ -0,0 +1,12 @@
--TEST--
Multiple typed constants in one declaration
--FILE--
<?php
class Test {
public const int X = 1, Y = "foo";
}
?>
--EXPECTF--
Fatal error: Cannot use string as value for class constant Test::Y of type int in %s on line %d

View file

@ -1924,6 +1924,10 @@ simple_list:
zend_ast_export_visibility(str, ast->attr); zend_ast_export_visibility(str, ast->attr);
smart_str_appends(str, "const "); smart_str_appends(str, "const ");
if (ast->child[2]) {
zend_ast_export_type(str, ast->child[2], indent);
smart_str_appendc(str, ' ');
}
ast = ast->child[0]; ast = ast->child[0];

View file

@ -145,7 +145,6 @@ enum _zend_ast_kind {
ZEND_AST_USE_ELEM, ZEND_AST_USE_ELEM,
ZEND_AST_TRAIT_ALIAS, ZEND_AST_TRAIT_ALIAS,
ZEND_AST_GROUP_USE, ZEND_AST_GROUP_USE,
ZEND_AST_CLASS_CONST_GROUP,
ZEND_AST_ATTRIBUTE, ZEND_AST_ATTRIBUTE,
ZEND_AST_MATCH, ZEND_AST_MATCH,
ZEND_AST_MATCH_ARM, ZEND_AST_MATCH_ARM,
@ -161,6 +160,8 @@ enum _zend_ast_kind {
ZEND_AST_CATCH, ZEND_AST_CATCH,
ZEND_AST_PROP_GROUP, ZEND_AST_PROP_GROUP,
ZEND_AST_PROP_ELEM, ZEND_AST_PROP_ELEM,
ZEND_AST_CONST_ELEM,
ZEND_AST_CLASS_CONST_GROUP,
// Pseudo node for initializing enums // Pseudo node for initializing enums
ZEND_AST_CONST_ENUM_INIT, ZEND_AST_CONST_ENUM_INIT,
@ -169,7 +170,6 @@ enum _zend_ast_kind {
ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT,
ZEND_AST_FOREACH, ZEND_AST_FOREACH,
ZEND_AST_ENUM_CASE, ZEND_AST_ENUM_CASE,
ZEND_AST_CONST_ELEM,
/* 5 child nodes */ /* 5 child nodes */
ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT, ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT,

View file

@ -7693,7 +7693,7 @@ static void zend_check_trait_alias_modifiers(uint32_t attr) /* {{{ */
} }
/* }}} */ /* }}} */
static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast) static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_ast *attr_ast, zend_ast *type_ast)
{ {
zend_ast_list *list = zend_ast_get_list(ast); zend_ast_list *list = zend_ast_get_list(ast);
zend_class_entry *ce = CG(active_class_entry); zend_class_entry *ce = CG(active_class_entry);
@ -7705,7 +7705,6 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
zend_ast *name_ast = const_ast->child[0]; zend_ast *name_ast = const_ast->child[0];
zend_ast **value_ast_ptr = &const_ast->child[1]; zend_ast **value_ast_ptr = &const_ast->child[1];
zend_ast *doc_comment_ast = const_ast->child[2]; zend_ast *doc_comment_ast = const_ast->child[2];
zend_ast *type_ast = const_ast->child[3];
zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast)); zend_string *name = zval_make_interned_string(zend_ast_get_zval(name_ast));
zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL; zend_string *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zval value_zv; zval value_zv;
@ -7752,8 +7751,9 @@ static void zend_compile_class_const_group(zend_ast *ast) /* {{{ */
{ {
zend_ast *const_ast = ast->child[0]; zend_ast *const_ast = ast->child[0];
zend_ast *attr_ast = ast->child[1]; zend_ast *attr_ast = ast->child[1];
zend_ast *type_ast = ast->child[2];
zend_compile_class_const_decl(const_ast, ast->attr, attr_ast); zend_compile_class_const_decl(const_ast, ast->attr, attr_ast, type_ast);
} }
/* }}} */ /* }}} */

View file

@ -267,7 +267,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%type <ast> echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list %type <ast> echo_expr_list unset_variables catch_name_list catch_list optional_variable parameter_list class_statement_list
%type <ast> implements_list case_list if_stmt_without_else %type <ast> implements_list case_list if_stmt_without_else
%type <ast> non_empty_parameter_list argument_list non_empty_argument_list property_list %type <ast> non_empty_parameter_list argument_list non_empty_argument_list property_list
%type <ast> class_const_list first_class_const_decl class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs %type <ast> class_const_list class_const_decl class_name_list trait_adaptations method_body non_empty_for_exprs
%type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars %type <ast> ctor_arguments alt_if_stmt_without_else trait_adaptation_list lexical_vars
%type <ast> lexical_var_list encaps_list %type <ast> lexical_var_list encaps_list
%type <ast> array_pair non_empty_array_pair_list array_pair_list possible_array_pair %type <ast> array_pair non_empty_array_pair_list array_pair_list possible_array_pair
@ -940,7 +940,10 @@ attributed_class_statement:
{ $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL); { $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL);
$$->attr = $1; } $$->attr = $1; }
| class_const_modifiers T_CONST class_const_list ';' | class_const_modifiers T_CONST class_const_list ';'
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $3, NULL); { $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $3, NULL, NULL);
$$->attr = $1; }
| class_const_modifiers T_CONST type_expr class_const_list ';'
{ $$ = zend_ast_create(ZEND_AST_CLASS_CONST_GROUP, $4, NULL, $3);
$$->attr = $1; } $$->attr = $1; }
| method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')' | method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')'
return_type backup_fn_flags method_body backup_fn_flags return_type backup_fn_flags method_body backup_fn_flags
@ -1076,21 +1079,20 @@ property:
class_const_list: class_const_list:
class_const_list ',' class_const_decl { $$ = zend_ast_list_add($1, $3); } class_const_list ',' class_const_decl { $$ = zend_ast_list_add($1, $3); }
| first_class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); } | class_const_decl { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); }
;
first_class_const_decl:
T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); }
| semi_reserved '=' expr backup_doc_comment { zval zv; if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; } $$ = zend_ast_create(ZEND_AST_CONST_ELEM, zend_ast_create_zval(&zv), $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); }
| type_expr identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $2, $4, ($5 ? zend_ast_create_zval_from_str($5) : NULL), $1); }
; ;
class_const_decl: class_const_decl:
identifier '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
| semi_reserved '=' expr backup_doc_comment {
zval zv;
if (zend_lex_tstring(&zv, $1) == FAILURE) { YYABORT; }
$$ = zend_ast_create(ZEND_AST_CONST_ELEM, zend_ast_create_zval(&zv), $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL));
}
; ;
const_decl: const_decl:
T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL), NULL); } T_STRING '=' expr backup_doc_comment { $$ = zend_ast_create(ZEND_AST_CONST_ELEM, $1, $3, ($4 ? zend_ast_create_zval_from_str($4) : NULL)); }
; ;
echo_expr_list: echo_expr_list: