From 747dd1c3c1ae55017525dde5e962a2f7c075f023 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 22 Jul 2022 16:26:56 +0200 Subject: [PATCH] Fix arrow function with never return type Fixes GH-7900 Closees GH-9103 --- Zend/tests/gh7900.phpt | 26 ++++++++++++++++++++++++++ Zend/zend_ast.c | 7 +++++-- Zend/zend_compile.c | 13 +++++++++++++ Zend/zend_language_parser.y | 3 +-- 4 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 Zend/tests/gh7900.phpt diff --git a/Zend/tests/gh7900.phpt b/Zend/tests/gh7900.phpt new file mode 100644 index 000000000000..a4170fb1278f --- /dev/null +++ b/Zend/tests/gh7900.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-7900: Arrow function with never return type compile-time errors +--INI-- +zend.assertions=1 +assert.exception=1 +--FILE-- + throw new \Exception('Here'); + +try { + var_dump($x()); +} catch (\Exception $e) { + echo $e->getMessage(), "\n"; +} + +try { + assert((fn(): never => 42) && false); +} catch (\Error $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Here +assert(fn(): never => 42 && false) diff --git a/Zend/zend_ast.c b/Zend/zend_ast.c index 6bdf0c4e3888..9fbfcd4c202f 100644 --- a/Zend/zend_ast.c +++ b/Zend/zend_ast.c @@ -1761,9 +1761,12 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio } if (decl->child[2]) { if (decl->kind == ZEND_AST_ARROW_FUNC) { - ZEND_ASSERT(decl->child[2]->kind == ZEND_AST_RETURN); + zend_ast *body = decl->child[2]; + if (body->kind == ZEND_AST_RETURN) { + body = body->child[0]; + } smart_str_appends(str, " => "); - zend_ast_export_ex(str, decl->child[2]->child[0], 0, indent); + zend_ast_export_ex(str, body, 0, indent); break; } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ff7c9b152cd7..c57b7c1d616a 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -7349,6 +7349,19 @@ static void zend_compile_func_decl(znode *result, zend_ast *ast, bool toplevel) } else if (uses_ast) { zend_compile_closure_uses(uses_ast); } + + if (ast->kind == ZEND_AST_ARROW_FUNC) { + bool needs_return = true; + if (op_array->fn_flags & ZEND_ACC_HAS_RETURN_TYPE) { + zend_arg_info *return_info = CG(active_op_array)->arg_info - 1; + needs_return = !ZEND_TYPE_CONTAINS_CODE(return_info->type, IS_NEVER); + } + if (needs_return) { + stmt_ast = zend_ast_create(ZEND_AST_RETURN, stmt_ast); + decl->child[2] = stmt_ast; + } + } + zend_compile_stmt(stmt_ast); if (is_method) { diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 5dcda82a3660..7194f70b9d47 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -1222,8 +1222,7 @@ inline_function: | fn returns_ref backup_doc_comment '(' parameter_list ')' return_type T_DOUBLE_ARROW backup_fn_flags backup_lex_pos expr backup_fn_flags { $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $12, $1, $3, - zend_string_init("{closure}", sizeof("{closure}") - 1, 0), $5, NULL, - zend_ast_create(ZEND_AST_RETURN, $11), $7, NULL); + zend_string_init("{closure}", sizeof("{closure}") - 1, 0), $5, NULL, $11, $7, NULL); ((zend_ast_decl *) $$)->lex_pos = $10; CG(extra_fn_flags) = $9; } ;