Skip to content

Correctly handle multiple constants in typed declaration #11286

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions Zend/tests/type_declarations/typed_class_constants_ast_print.phpt
Original file line number Diff line number Diff line change
@@ -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;
})
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions Zend/zend_ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -1924,6 +1924,10 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio

zend_ast_export_visibility(str, ast->attr);
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];

Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ enum _zend_ast_kind {
ZEND_AST_USE_ELEM,
ZEND_AST_TRAIT_ALIAS,
ZEND_AST_GROUP_USE,
ZEND_AST_CLASS_CONST_GROUP,
ZEND_AST_ATTRIBUTE,
ZEND_AST_MATCH,
ZEND_AST_MATCH_ARM,
Expand All @@ -161,6 +160,8 @@ enum _zend_ast_kind {
ZEND_AST_CATCH,
ZEND_AST_PROP_GROUP,
ZEND_AST_PROP_ELEM,
ZEND_AST_CONST_ELEM,
ZEND_AST_CLASS_CONST_GROUP,

// Pseudo node for initializing enums
ZEND_AST_CONST_ENUM_INIT,
Expand All @@ -169,7 +170,6 @@ enum _zend_ast_kind {
ZEND_AST_FOR = 4 << ZEND_AST_NUM_CHILDREN_SHIFT,
ZEND_AST_FOREACH,
ZEND_AST_ENUM_CASE,
ZEND_AST_CONST_ELEM,

/* 5 child nodes */
ZEND_AST_PARAM = 5 << ZEND_AST_NUM_CHILDREN_SHIFT,
Expand Down
6 changes: 3 additions & 3 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_class_entry *ce = CG(active_class_entry);
Expand All @@ -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 **value_ast_ptr = &const_ast->child[1];
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 *doc_comment = doc_comment_ast ? zend_string_copy(zend_ast_get_str(doc_comment_ast)) : NULL;
zval value_zv;
Expand Down Expand Up @@ -7752,8 +7751,9 @@ static void zend_compile_class_const_group(zend_ast *ast) /* {{{ */
{
zend_ast *const_ast = ast->child[0];
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);
}
/* }}} */

Expand Down
24 changes: 13 additions & 11 deletions Zend/zend_language_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -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> implements_list case_list if_stmt_without_else
%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> lexical_var_list encaps_list
%type <ast> array_pair non_empty_array_pair_list array_pair_list possible_array_pair
Expand Down Expand Up @@ -940,7 +940,10 @@ attributed_class_statement:
{ $$ = zend_ast_create(ZEND_AST_PROP_GROUP, $2, $3, NULL);
$$->attr = $1; }
| 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; }
| method_modifiers function returns_ref identifier backup_doc_comment '(' parameter_list ')'
return_type backup_fn_flags method_body backup_fn_flags
Expand Down Expand Up @@ -1076,21 +1079,20 @@ property:

class_const_list:
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); }
;

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 { $$ = zend_ast_create_list(1, ZEND_AST_CLASS_CONST_DECL, $1); }
;

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:
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:
Expand Down