Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 8.1k
[PFA 1/n] Support PFA syntax#20717
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
Uh oh!
There was an error while loading. Please reload this page.
[PFA 1/n] Support PFA syntax #20717
Changes from all commits
677e251905b3111ac09e0a65e668098862d54b61c8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --TEST-- | ||
| First class callable error: more than one argument | ||
| --FILE-- | ||
| <?php | ||
| foo(1, ...); | ||
| ?> | ||
| --EXPECTF-- | ||
| Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| --TEST-- | ||
| First class callable error: non-variadic placeholder | ||
| --FILE-- | ||
| <?php | ||
| foo(?); | ||
| ?> | ||
| --EXPECTF-- | ||
| Fatal error: Cannot create a Closure for call expression with more than one argument, or non-variadic placeholders in %s on line %d |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -54,13 +54,14 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_znode(const znode *node) { | ||
| return (zend_ast *) ast; | ||
| } | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(void) { | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_fcc(zend_ast *args) { | ||
| zend_ast_fcc *ast; | ||
| ast = zend_ast_alloc(sizeof(zend_ast_fcc)); | ||
| ast->kind = ZEND_AST_CALLABLE_CONVERT; | ||
| ast->attr = 0; | ||
| ast->lineno = CG(zend_lineno); | ||
| ast->args = args; | ||
| ZEND_MAP_PTR_INIT(ast->fptr, NULL); | ||
| return (zend_ast *) ast; | ||
| @@ -157,6 +158,12 @@ ZEND_API zend_ast *zend_ast_create_decl( | ||
| return (zend_ast *) ast; | ||
| } | ||
| static bool zend_ast_is_placeholder_arg(zend_ast *arg) { | ||
| return arg->kind == ZEND_AST_PLACEHOLDER_ARG | ||
| || (arg->kind == ZEND_AST_NAMED_ARG | ||
| && arg->child[1]->kind == ZEND_AST_PLACEHOLDER_ARG); | ||
| } | ||
| #if ZEND_AST_SPEC | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_0(zend_ast_kind kind) { | ||
| zend_ast *ast; | ||
| @@ -400,6 +407,30 @@ ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_list_2(zend_ast_kind kind, zen | ||
| return ast; | ||
| } | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_0(zend_ast_kind kind) { | ||
| return zend_ast_create_list(0, kind); | ||
| } | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_1(zend_ast_kind kind, zend_ast *arg) { | ||
| zend_ast *list = zend_ast_create_list(1, kind, arg); | ||
| if (zend_ast_is_placeholder_arg(arg)) { | ||
| return zend_ast_create_fcc(list); | ||
| } | ||
| return list; | ||
| } | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_create_arg_list_2(zend_ast_kind kind, zend_ast *arg1, zend_ast *arg2) { | ||
| zend_ast *list = zend_ast_create_list(2, kind, arg1, arg2); | ||
| if (zend_ast_is_placeholder_arg(arg1) || zend_ast_is_placeholder_arg(arg2)) { | ||
| return zend_ast_create_fcc(list); | ||
| } | ||
| return list; | ||
| } | ||
| #else | ||
| static zend_ast *zend_ast_create_from_va_list(zend_ast_kind kind, zend_ast_attr attr, va_list va) { | ||
| uint32_t i, children = kind >> ZEND_AST_NUM_CHILDREN_SHIFT; | ||
| @@ -479,6 +510,41 @@ ZEND_API zend_ast *zend_ast_create_list(uint32_t init_children, zend_ast_kind ki | ||
| return ast; | ||
| } | ||
| ZEND_API zend_ast *zend_ast_create_arg_list(uint32_t init_children, zend_ast_kind kind, ...) { | ||
| zend_ast *ast; | ||
| zend_ast_list *list; | ||
| bool has_placeholders = false; | ||
| ast = zend_ast_alloc(zend_ast_list_size(4)); | ||
| list = (zend_ast_list *) ast; | ||
| list->kind = kind; | ||
| list->attr = 0; | ||
| list->lineno = CG(zend_lineno); | ||
| list->children = 0; | ||
| { | ||
| va_list va; | ||
| uint32_t i; | ||
| va_start(va, kind); | ||
| for (i = 0; i < init_children; ++i) { | ||
| zend_ast *child = va_arg(va, zend_ast *); | ||
| ast = zend_ast_list_add(ast, child); | ||
| uint32_t lineno = zend_ast_get_lineno(child); | ||
| if (lineno < ast->lineno) { | ||
| ast->lineno = lineno; | ||
| } | ||
| has_placeholders = has_placeholders || zend_ast_is_placeholder_arg(child); | ||
| } | ||
| va_end(va); | ||
| } | ||
| if (has_placeholders) { | ||
| return zend_ast_create_fcc(list); | ||
| } | ||
| return ast; | ||
| } | ||
| #endif | ||
| zend_ast *zend_ast_create_concat_op(zend_ast *op0, zend_ast *op1) { | ||
| @@ -508,6 +574,23 @@ ZEND_ATTRIBUTE_NODISCARD ZEND_API zend_ast * ZEND_FASTCALL zend_ast_list_add(zen | ||
| return (zend_ast *) list; | ||
| } | ||
| ZEND_API zend_ast * ZEND_FASTCALL zend_ast_arg_list_add(zend_ast *list, zend_ast *arg) | ||
| { | ||
| if (list->kind == ZEND_AST_CALLABLE_CONVERT) { | ||
| zend_ast_fcc *fcc_ast = (zend_ast_fcc*)list; | ||
| fcc_ast->args = zend_ast_list_add(fcc_ast->args, arg); | ||
| return (zend_ast*)fcc_ast; | ||
| } | ||
| ZEND_ASSERT(list->kind == ZEND_AST_ARG_LIST); | ||
| if (zend_ast_is_placeholder_arg(arg)) { | ||
| return zend_ast_create_fcc(zend_ast_list_add(list, arg)); | ||
| } | ||
| return zend_ast_list_add(list, arg); | ||
| } | ||
| static zend_result zend_ast_add_array_element(const zval *result, zval *offset, zval *expr) | ||
| { | ||
| if (Z_TYPE_P(offset) == IS_UNDEF) { | ||
| @@ -1060,6 +1143,15 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( | ||
| case ZEND_AST_CALL: { | ||
| ZEND_ASSERT(ast->child[1]->kind == ZEND_AST_CALLABLE_CONVERT); | ||
| zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[1]; | ||
| zend_ast_list *args = zend_ast_get_list(fcc_ast->args); | ||
| ZEND_ASSERT(args->children > 0); | ||
| if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) { | ||
| /* TODO: PFAs */ | ||
arnaud-lb marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); | ||
| return FAILURE; | ||
| } | ||
| fptr = ZEND_MAP_PTR_GET(fcc_ast->fptr); | ||
| if (!fptr) { | ||
| @@ -1087,6 +1179,14 @@ static zend_result ZEND_FASTCALL zend_ast_evaluate_inner( | ||
| ZEND_ASSERT(ast->child[2]->kind == ZEND_AST_CALLABLE_CONVERT); | ||
| zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast->child[2]; | ||
| zend_ast_list *args = zend_ast_get_list(fcc_ast->args); | ||
| ZEND_ASSERT(args->children > 0); | ||
| if (args->children != 1 || args->child[0]->attr != ZEND_PLACEHOLDER_VARIADIC) { | ||
| /* TODO: PFAs */ | ||
| zend_error_noreturn(E_COMPILE_ERROR, "Constant expression contains invalid operations"); | ||
| return FAILURE; | ||
| } | ||
| zend_class_entry *ce = zend_ast_fetch_class(ast->child[0], scope); | ||
| if (!ce) { | ||
| return FAILURE; | ||
| @@ -1243,7 +1343,8 @@ static size_t ZEND_FASTCALL zend_ast_tree_size(zend_ast *ast) | ||
| } else if (ast->kind == ZEND_AST_OP_ARRAY) { | ||
| size = sizeof(zend_ast_op_array); | ||
| } else if (ast->kind == ZEND_AST_CALLABLE_CONVERT) { | ||
| size = sizeof(zend_ast_fcc); | ||
| zend_ast *args_ast = ((zend_ast_fcc*)ast)->args; | ||
| size = sizeof(zend_ast_fcc) + zend_ast_tree_size(args_ast); | ||
| } else if (zend_ast_is_list(ast)) { | ||
| uint32_t i; | ||
| const zend_ast_list *list = zend_ast_get_list(ast); | ||
| @@ -1320,6 +1421,8 @@ static void* ZEND_FASTCALL zend_ast_tree_copy(zend_ast *ast, void *buf) | ||
| new->lineno = old->lineno; | ||
| ZEND_MAP_PTR_INIT(new->fptr, ZEND_MAP_PTR(old->fptr)); | ||
| buf = (void*)((char*)buf + sizeof(zend_ast_fcc)); | ||
| new->args = buf; | ||
| buf = zend_ast_tree_copy(old->args, buf); | ||
| } else if (zend_ast_is_decl(ast)) { | ||
| /* Not implemented. */ | ||
| ZEND_UNREACHABLE(); | ||
| @@ -1403,6 +1506,11 @@ ZEND_API void ZEND_FASTCALL zend_ast_destroy(zend_ast *ast) | ||
| zend_ast_destroy(decl->child[3]); | ||
| ast = decl->child[4]; | ||
| goto tail_call; | ||
| } else if (EXPECTED(ast->kind == ZEND_AST_CALLABLE_CONVERT)) { | ||
| zend_ast_fcc *fcc_ast = (zend_ast_fcc*) ast; | ||
| ast = fcc_ast->args; | ||
| goto tail_call; | ||
| } | ||
| } | ||
| @@ -2299,6 +2407,13 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio | ||
| EMPTY_SWITCH_DEFAULT_CASE(); | ||
| } | ||
| break; | ||
| case ZEND_AST_PLACEHOLDER_ARG: | ||
| if (ast->attr == ZEND_PLACEHOLDER_VARIADIC) { | ||
| APPEND_STR("..."); | ||
| } else { | ||
| APPEND_STR("?"); | ||
| } | ||
| break; | ||
| /* 1 child node */ | ||
| case ZEND_AST_VAR: | ||
| @@ -2445,9 +2560,11 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio | ||
| zend_ast_export_ex(str, ast->child[1], 0, indent); | ||
| smart_str_appendc(str, ')'); | ||
| break; | ||
| case ZEND_AST_CALLABLE_CONVERT: | ||
| smart_str_appends(str, "..."); | ||
| break; | ||
| case ZEND_AST_CALLABLE_CONVERT: { | ||
| zend_ast_fcc *fcc_ast = (zend_ast_fcc*)ast; | ||
| ast = fcc_ast->args; | ||
| goto simple_list; | ||
| } | ||
| case ZEND_AST_CLASS_CONST: | ||
| zend_ast_export_ns_name(str, ast->child[0], 0, indent); | ||
| smart_str_appends(str, "::"); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -901,16 +901,15 @@ return_type: | ||
| ; | ||
| argument_list: | ||
| '(' ')' { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } | ||
| '(' ')' { $$ = zend_ast_create_arg_list(0, ZEND_AST_ARG_LIST); } | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. zend_ast_create_arg_list is always used with ZEND_AST_ARG_LIST. Looks a bit redundant but perhaps this is for the future proofing.
| ||
| | '(' non_empty_argument_list possible_comma ')' { $$ = $2; } | ||
| | '(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); } | ||
| ; | ||
| non_empty_argument_list: | ||
| argument | ||
| { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); } | ||
| { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $1); } | ||
| | non_empty_argument_list ',' argument | ||
| { $$ = zend_ast_list_add($1, $3); } | ||
| { $$ = zend_ast_arg_list_add($1, $3); } | ||
| ; | ||
| /* `clone_argument_list` is necessary to resolve a parser ambiguity (shift-reduce conflict) | ||
| @@ -923,25 +922,31 @@ non_empty_argument_list: | ||
| * syntax. | ||
| */ | ||
| clone_argument_list: | ||
| '(' ')' { $$ = zend_ast_create_list(0, ZEND_AST_ARG_LIST); } | ||
| '(' ')' { $$ = zend_ast_create_arg_list(0, ZEND_AST_ARG_LIST); } | ||
| | '(' non_empty_clone_argument_list possible_comma ')' { $$ = $2; } | ||
| | '(' expr ',' ')' { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $2); } | ||
| | '(' T_ELLIPSIS ')' { $$ = zend_ast_create_fcc(); } | ||
| | '(' expr ',' ')' { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $2); } | ||
| ; | ||
| non_empty_clone_argument_list: | ||
| expr ',' argument | ||
| { $$ = zend_ast_create_list(2, ZEND_AST_ARG_LIST, $1, $3); } | ||
| { $$ = zend_ast_create_arg_list(2, ZEND_AST_ARG_LIST, $1, $3); } | ||
| | argument_no_expr | ||
| { $$ = zend_ast_create_list(1, ZEND_AST_ARG_LIST, $1); } | ||
| { $$ = zend_ast_create_arg_list(1, ZEND_AST_ARG_LIST, $1); } | ||
| | non_empty_clone_argument_list ',' argument | ||
| { $$ = zend_ast_list_add($1, $3); } | ||
| { $$ = zend_ast_arg_list_add($1, $3); } | ||
| ; | ||
| argument_no_expr: | ||
| identifier ':' expr | ||
| { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, $3); } | ||
| | T_ELLIPSIS expr { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } | ||
| | T_ELLIPSIS | ||
| { $$ = zend_ast_create_ex(ZEND_AST_PLACEHOLDER_ARG, ZEND_PLACEHOLDER_VARIADIC); } | ||
| | '?' | ||
| { $$ = zend_ast_create(ZEND_AST_PLACEHOLDER_ARG); } | ||
| | identifier ':' '?' | ||
| { $$ = zend_ast_create(ZEND_AST_NAMED_ARG, $1, zend_ast_create(ZEND_AST_PLACEHOLDER_ARG)); } | ||
| | T_ELLIPSIS expr | ||
| { $$ = zend_ast_create(ZEND_AST_UNPACK, $2); } | ||
| ; | ||
| argument: | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is clearer (the
fcc_astdoesn't actually change):There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer
return (zend_ast*)fcc_ast, but no strong opinion