Skip to content

Commit 04a31ab

Browse files
committed
Switch to more explicit <- returns, allow omitting <- for terminating blocks
1 parent 3ccbc43 commit 04a31ab

23 files changed

+641
-583
lines changed

Zend/Optimizer/dce.c

+1
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ static inline bool may_have_side_effects(
154154
case ZEND_INCLUDE_OR_EVAL:
155155
case ZEND_THROW:
156156
case ZEND_MATCH_ERROR:
157+
case ZEND_MATCH_BLOCK_NO_VALUE_ERROR:
157158
case ZEND_EXT_STMT:
158159
case ZEND_EXT_FCALL_BEGIN:
159160
case ZEND_EXT_FCALL_END:

Zend/tests/match/block_arg_return.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Match expression block must not use return
33
--FILE--
44
<?php
55
foo(match (1) {
6-
1 => { return; null }
6+
1 => { return; }
77
});
88
?>
99
--EXPECTF--

Zend/tests/match/block_basic.phpt

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ function bar() {
1212

1313
function test($value) {
1414
var_dump(match ($value) {
15-
1 => { 1 },
16-
2 => { $x = 2; $x },
15+
1 => { <- 1; },
16+
2 => {
17+
$x = 2;
18+
<- $x;
19+
},
1720
3 => {
1821
foo();
19-
bar()
22+
<- bar();
2023
},
2124
});
2225
}

Zend/tests/match/block_expr_break_escape.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Match expression block must not use break
33
--FILE--
44
<?php
55
var_dump(match ($value) {
6-
1 => { break; [] },
6+
1 => { break; },
77
});
88
?>
99
--EXPECTF--

Zend/tests/match/block_expr_break_no_escape.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ var_dump(match (1) {
88
echo $value, "\n";
99
break;
1010
}
11-
42
11+
<- 42;
1212
},
1313
});
1414
?>

Zend/tests/match/block_expr_goto_escape.phpt

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ Match expression block must not use goto
55
var_dump(match (1) {
66
1 => {
77
goto after;
8-
42
98
},
109
});
1110
after:

Zend/tests/match/block_expr_goto_into.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ goto in;
66
var_dump(match (1) {
77
1 => {
88
in:
9-
42
9+
<- 42;
1010
},
1111
});
1212
?>

Zend/tests/match/block_expr_no_result.phpt

+15-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,19 @@
22
Match expression block must return a value
33
--FILE--
44
<?php
5-
var_dump(match (1) {
6-
1 => {
7-
echo "Not returning anything\n";
8-
},
9-
});
5+
function test() {
6+
var_dump(match (1) {
7+
1 => {
8+
echo "Not returning anything\n";
9+
},
10+
});
11+
}
12+
try {
13+
test();
14+
} catch (Error $e) {
15+
echo $e->getMessage(), "\n";
16+
}
1017
?>
11-
--EXPECTF--
12-
Fatal error: Blocks of match expression with used result must return a value. Did you mean to omit the last semicolon? in %s on line %d
18+
--EXPECT--
19+
Not returning anything
20+
Match expected a value from block but none was returned

Zend/tests/match/block_expr_return.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Match expression block must not use return
33
--FILE--
44
<?php
55
var_dump(match ($value) {
6-
1 => { return; [] },
6+
1 => { return; },
77
});
88
?>
99
--EXPECTF--

Zend/tests/match/block_expr_throw.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Throwing match expression block must clean up live-vars
55

66
function throw_($value) {
77
var_dump([new \stdClass] + match ($value) {
8-
1 => { throw new Exception('Exception with live var'); [] },
8+
1 => { throw new Exception('Exception with live var'); },
99
});
1010
}
1111

Zend/tests/match/block_stmt_with_result.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Match statement block must not return a value
33
--FILE--
44
<?php
55
match (1) {
6-
1 => { 42 },
6+
1 => { <- 42; },
77
};
88
?>
99
--EXPECTF--

Zend/zend_compile.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -6058,13 +6058,15 @@ static void zend_compile_match(znode *result, zend_ast *ast)
60586058
CG(context).in_block_expr = true;
60596059
zend_compile_stmt_list(body_ast->child[0]);
60606060
zend_ast *result_expr_ast = body_ast->child[1];
6061-
if (result && !result_expr_ast) {
6062-
zend_error_noreturn(E_COMPILE_ERROR, "Blocks of match expression with used result must return a value. Did you mean to omit the last semicolon?");
6063-
} else if (!result && result_expr_ast) {
6061+
if (!result && result_expr_ast) {
60646062
zend_error_noreturn(E_COMPILE_ERROR, "Blocks of match expression with unused result must not return a value");
60656063
}
60666064
if (result_expr_ast) {
60676065
zend_compile_expr(&body_node, result_expr_ast);
6066+
} else if (result) {
6067+
zend_emit_op(NULL, ZEND_MATCH_BLOCK_NO_VALUE_ERROR, NULL, NULL);
6068+
body_node.op_type = IS_CONST;
6069+
ZVAL_NULL(&body_node.u.constant);
60686070
}
60696071
CG(context).in_block_expr = prev_in_block_expr;
60706072
} else {

Zend/zend_execute.c

+5
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,11 @@ ZEND_COLD void zend_match_unhandled_error(const zval *value)
887887
smart_str_free(&msg);
888888
}
889889

890+
ZEND_COLD void zend_match_block_no_value_error(void)
891+
{
892+
zend_throw_exception_ex(zend_ce_unhandled_match_error, 0, "Match expected a value from block but none was returned");
893+
}
894+
890895
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_readonly_property_modification_error(
891896
const zend_property_info *info) {
892897
zend_throw_error(NULL, "Cannot modify readonly property %s::$%s",

Zend/zend_language_parser.y

+7-2
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
7070
%left '^'
7171
%left T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG
7272
%nonassoc T_IS_EQUAL T_IS_NOT_EQUAL T_IS_IDENTICAL T_IS_NOT_IDENTICAL T_SPACESHIP
73-
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL
73+
%nonassoc '<' T_IS_SMALLER_OR_EQUAL '>' T_IS_GREATER_OR_EQUAL T_THIN_ARROW_LEFT
7474
%left '.'
7575
%left T_SL T_SR
7676
%left '+' '-'
@@ -216,6 +216,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
216216
%token T_OBJECT_OPERATOR "'->'"
217217
%token T_NULLSAFE_OBJECT_OPERATOR "'?->'"
218218
%token T_DOUBLE_ARROW "'=>'"
219+
%token T_THIN_ARROW_LEFT "'<-'"
219220
%token T_COMMENT "comment"
220221
%token T_DOC_COMMENT "doc comment"
221222
%token T_OPEN_TAG "open tag"
@@ -739,7 +740,8 @@ match_arm_cond_list:
739740

740741
match_arm_body:
741742
expr { $$ = $1; }
742-
| '{' inner_statement_list optional_expr '}' { $$ = zend_ast_create(ZEND_AST_MATCH_ARM_BLOCK, $2, $3); }
743+
| '{' inner_statement_list '}' { $$ = zend_ast_create(ZEND_AST_MATCH_ARM_BLOCK, $2, NULL); }
744+
| '{' inner_statement_list T_THIN_ARROW_LEFT optional_expr ';' '}' { $$ = zend_ast_create(ZEND_AST_MATCH_ARM_BLOCK, $2, $4); }
743745
;
744746

745747
while_statement:
@@ -1215,6 +1217,9 @@ expr:
12151217
{ $$ = zend_ast_create_binary_op(ZEND_IS_NOT_EQUAL, $1, $3); }
12161218
| expr '<' expr
12171219
{ $$ = zend_ast_create_binary_op(ZEND_IS_SMALLER, $1, $3); }
1220+
/* BC for $foo<-$bar */
1221+
| expr T_THIN_ARROW_LEFT expr
1222+
{ $$ = zend_ast_create_binary_op(ZEND_IS_SMALLER, $1, zend_ast_create(ZEND_AST_UNARY_MINUS, $3)); }
12181223
| expr T_IS_SMALLER_OR_EQUAL expr
12191224
{ $$ = zend_ast_create_binary_op(ZEND_IS_SMALLER_OR_EQUAL, $1, $3); }
12201225
| expr '>' expr

Zend/zend_language_scanner.l

+4
Original file line numberDiff line numberDiff line change
@@ -1603,6 +1603,10 @@ OPTIONAL_WHITESPACE_OR_COMMENTS ({WHITESPACE}|{MULTI_LINE_COMMENT}|{SINGLE_LINE_
16031603
goto restart;
16041604
}
16051605

1606+
<ST_IN_SCRIPTING>"<-" {
1607+
RETURN_TOKEN(T_THIN_ARROW_LEFT);
1608+
}
1609+
16061610
<ST_IN_SCRIPTING>"::" {
16071611
RETURN_TOKEN(T_PAAMAYIM_NEKUDOTAYIM);
16081612
}

Zend/zend_vm_def.h

+7
Original file line numberDiff line numberDiff line change
@@ -9217,6 +9217,13 @@ ZEND_VM_COLD_CONST_HANDLER(197, ZEND_MATCH_ERROR, CONST|TMPVARCV, UNUSED)
92179217
HANDLE_EXCEPTION();
92189218
}
92199219

9220+
ZEND_VM_COLD_CONST_HANDLER(204, ZEND_MATCH_BLOCK_NO_VALUE_ERROR, UNUSED, UNUSED)
9221+
{
9222+
SAVE_OPLINE();
9223+
zend_match_block_no_value_error();
9224+
HANDLE_EXCEPTION();
9225+
}
9226+
92209227
ZEND_VM_COLD_CONSTCONST_HANDLER(189, ZEND_IN_ARRAY, CONST|TMP|VAR|CV, CONST, NUM)
92219228
{
92229229
USE_OPLINE

0 commit comments

Comments
 (0)