Skip to content

Commit 8a9ee8b

Browse files
committed
Adds support to multi-line arrow functions
1 parent 9a1da9f commit 8a9ee8b

File tree

10 files changed

+195
-20
lines changed

10 files changed

+195
-20
lines changed

Zend/tests/arrow_functions/001.phpt

Lines changed: 54 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,87 @@ Basic arrow function functionality check
33
--FILE--
44
<?php
55

6+
// No return value
7+
$foo = fn() => {};
8+
var_dump($foo());
9+
10+
// Return value
611
$foo = fn() => 1;
712
var_dump($foo());
813

14+
$foo = fn() => { return 2; };
15+
var_dump($foo());
16+
917
$foo = fn($x) => $x;
10-
var_dump($foo(2));
18+
var_dump($foo(3));
19+
20+
$foo = fn($x) => { return $x; };
21+
var_dump($foo(4));
1122

1223
$foo = fn($x, $y) => $x + $y;
13-
var_dump($foo(1, 2));
24+
var_dump($foo(4, 1));
25+
26+
$foo = fn($x, $y) => { return $x + $y; };
27+
var_dump($foo(5, 1));
1428

1529
// Closing over $var
16-
$var = 4;
30+
$var = 7;
1731
$foo = fn() => $var;
1832
var_dump($foo());
1933

34+
$var = 8;
35+
$foo = fn() => { return $var; };
36+
var_dump($foo());
37+
2038
// Not closing over $var, it's a parameter
2139
$foo = fn($var) => $var;
22-
var_dump($foo(5));
40+
var_dump($foo(9));
41+
42+
$foo = fn($var) => { return $var; };
43+
var_dump($foo(10));
2344

2445
// Close over $var by-value, not by-reference
25-
$var = 5;
46+
$var = 11;
2647
$foo = fn() => ++$var;
48+
var_dump($var);
2749
var_dump($foo());
50+
51+
$var = 13;
52+
$foo = fn() => { return ++$var; };
2853
var_dump($var);
54+
var_dump($foo());
2955

30-
// Nested arrow functions closing over variable
31-
$var = 6;
56+
// Nested arrow functions
57+
$var = 14;
3258
var_dump((fn() => fn() => $var)()());
59+
60+
$var = 15;
3361
var_dump((fn() => function() use($var) { return $var; })()());
3462

63+
$var = 16;
64+
var_dump((fn() => { return fn() => { return $var; }; })()());
65+
66+
// Nested arrow functions with null return value
67+
var_dump((fn() => { return fn() => {}; })()());
68+
3569
?>
3670
--EXPECT--
71+
NULL
3772
int(1)
3873
int(2)
3974
int(3)
4075
int(4)
4176
int(5)
4277
int(6)
43-
int(5)
44-
int(6)
45-
int(6)
78+
int(7)
79+
int(8)
80+
int(9)
81+
int(10)
82+
int(11)
83+
int(12)
84+
int(13)
85+
int(14)
86+
int(14)
87+
int(15)
88+
int(16)
89+
NULL

Zend/tests/arrow_functions/002.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ $b = 1;
77

88
var_dump((fn() => $b + $c)());
99

10+
$d = 2;
11+
var_dump((fn() => { return $d + $e; } )());
12+
1013
?>
1114
--EXPECTF--
1215
Warning: Undefined variable $c in %s on line %d
1316
int(1)
17+
18+
Warning: Undefined variable $e in %s on line %d
19+
int(2)

Zend/tests/arrow_functions/003.phpt

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,29 @@ $var = "a";
88
$fn = fn() => $$var;
99
var_dump($fn());
1010

11-
${5} = 2;
11+
$b = 2;
12+
$var = "b";
13+
$fn = fn() => { return $$var; };
14+
var_dump($fn());
15+
16+
${5} = 3;
1217
$fn = fn() => ${5};
1318
var_dump($fn());
1419

20+
${6} = 4;
21+
$fn = fn() => { return ${6}; };
22+
var_dump($fn());
23+
1524
?>
1625
--EXPECTF--
1726
Warning: Undefined variable $a in %s on line %d
1827
NULL
1928

29+
Warning: Undefined variable $b in %s on line %d
30+
NULL
31+
2032
Warning: Undefined variable $5 in %s on line %d
2133
NULL
34+
35+
Warning: Undefined variable $6 in %s on line %d
36+
NULL

Zend/tests/arrow_functions/004.phpt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ $a = 123;
88
$fn = fn() => $GLOBALS['a'];
99
var_dump($fn());
1010

11+
$a = 456;
12+
$fn = fn() => { return $GLOBALS['a']; };
13+
var_dump($fn());
14+
1115
?>
1216
--EXPECT--
1317
int(123)
18+
int(456)

Zend/tests/arrow_functions/005.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,47 @@ class Test {
1010
$r = new ReflectionFunction($fn);
1111
var_dump($r->getClosureThis());
1212

13+
$fn = fn() => {};
14+
$r = new ReflectionFunction($fn);
15+
var_dump($r->getClosureThis());
16+
1317
$fn = fn() => $this;
1418
var_dump($fn());
1519

20+
$fn = fn() => { return $this; };
21+
var_dump($fn());
22+
1623
$fn = fn() => Test::method2();
1724
$fn();
1825

26+
$fn = fn() => { return Test::method2(); };
27+
$fn();
28+
1929
$fn = fn() => call_user_func('Test::method2');
2030
$fn();
2131

32+
$fn = fn() => { return call_user_func('Test::method2'); };
33+
$fn();
34+
2235
$thisName = "this";
2336
$fn = fn() => $$thisName;
2437
var_dump($fn());
2538

39+
$fn = fn() => { return $$thisName; };
40+
var_dump($fn());
41+
2642
$fn = fn() => self::class;
2743
var_dump($fn());
2844

45+
$fn = fn() => { return self::class; };
46+
var_dump($fn());
47+
2948
// static can be used to unbind $this
3049
$fn = static fn() => isset($this);
3150
var_dump($fn());
51+
52+
$fn = static fn() => { return isset($this); };
53+
var_dump($fn());
3254
}
3355

3456
public function method2() {
@@ -50,5 +72,17 @@ object(Test)#1 (0) {
5072
}
5173
object(Test)#1 (0) {
5274
}
75+
object(Test)#1 (0) {
76+
}
77+
object(Test)#1 (0) {
78+
}
79+
object(Test)#1 (0) {
80+
}
81+
object(Test)#1 (0) {
82+
}
83+
object(Test)#1 (0) {
84+
}
85+
string(4) "Test"
5386
string(4) "Test"
5487
bool(false)
88+
bool(false)

Zend/tests/arrow_functions/006.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ $ref =& $id($var);
1010
$ref++;
1111
var_dump($var);
1212

13+
$id = fn&(&$x) => { return $x; };
14+
$ref =& $id($var);
15+
$ref++;
16+
var_dump($var);
17+
1318
// int argument and return type
1419
$var = 10;
1520
$int_fn = fn(int $x): int => $x;
@@ -20,6 +25,15 @@ try {
2025
echo $e->getMessage(), "\n";
2126
}
2227

28+
$var = 11;
29+
$int_fn = fn(int $x): int => { return $x; };
30+
var_dump($int_fn($var));
31+
try {
32+
$int_fn("foo");
33+
} catch (TypeError $e) {
34+
echo $e->getMessage(), "\n";
35+
}
36+
2337
$varargs = fn(?int... $args): array => $args;
2438
var_dump($varargs(20, null, 30));
2539
try {
@@ -28,11 +42,22 @@ try {
2842
echo $e->getMessage(), "\n";
2943
}
3044

45+
$varargs = fn(?int... $args): array => { return $args; };
46+
var_dump($varargs(40, null, 50));
47+
try {
48+
$varargs(60, "foo");
49+
} catch (TypeError $e) {
50+
echo $e->getMessage(), "\n";
51+
}
52+
3153
?>
3254
--EXPECTF--
3355
int(2)
56+
int(3)
3457
int(10)
3558
{closure}(): Argument #1 ($x) must be of type int, string given, called in %s on line %d
59+
int(11)
60+
{closure}(): Argument #1 ($x) must be of type int, string given, called in %s on line %d
3661
array(3) {
3762
[0]=>
3863
int(20)
@@ -42,3 +67,12 @@ array(3) {
4267
int(30)
4368
}
4469
{closure}(): Argument #2 must be of type ?int, string given, called in %s on line %d
70+
array(3) {
71+
[0]=>
72+
int(40)
73+
[1]=>
74+
NULL
75+
[2]=>
76+
int(50)
77+
}
78+
{closure}(): Argument #2 must be of type ?int, string given, called in %s on line %d

Zend/tests/arrow_functions/007.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,23 @@ assert.exception=0
88

99
// TODO We're missing parentheses for the direct call
1010
assert((fn() => false)());
11+
assert((fn() => { return false; })());
12+
1113
assert((fn&(int... $args): ?bool => $args[0])(false));
14+
assert((fn&(int... $args): ?bool => { return $args[0]; })(false));
1215

1316
?>
1417
--EXPECTF--
1518
Warning: assert(): assert(fn() => false()) failed in %s on line %d
1619

20+
Warning: assert(): assert(fn() {
21+
return false;
22+
}
23+
()) failed in %s on line %d
24+
1725
Warning: assert(): assert(fn&(int ...$args): ?bool => $args[0](false)) failed in %s on line %d
26+
27+
Warning: assert(): assert(fn&(int ...$args): ?bool {
28+
return $args[0];
29+
}
30+
(false)) failed in %s on line %d

Zend/tests/arrow_functions/008.phpt

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,43 @@ Yield inside arrow functions
55

66
// This doesn't make terribly much sense, but it works...
77

8-
$fn = fn() => yield 123;
8+
$fn = fn() => yield 1;
99
foreach ($fn() as $val) {
1010
var_dump($val);
1111
}
1212

13-
$fn = fn() => yield from [456, 789];
13+
$fn = fn() => { return yield 2; };
1414
foreach ($fn() as $val) {
1515
var_dump($val);
1616
}
1717

18-
$fn = fn() => fn() => yield 987;
18+
$fn = fn() => yield from [3, 4];
19+
foreach ($fn() as $val) {
20+
var_dump($val);
21+
}
22+
23+
$fn = fn() => { yield from [5, 6]; };
24+
foreach ($fn() as $val) {
25+
var_dump($val);
26+
}
27+
28+
$fn = fn() => fn() => yield 7;
29+
foreach ($fn()() as $val) {
30+
var_dump($val);
31+
}
32+
33+
$fn = fn() => fn() => { yield 8; };
1934
foreach ($fn()() as $val) {
2035
var_dump($val);
2136
}
2237

2338
?>
2439
--EXPECT--
25-
int(123)
26-
int(456)
27-
int(789)
28-
int(987)
40+
int(1)
41+
int(2)
42+
int(3)
43+
int(4)
44+
int(5)
45+
int(6)
46+
int(7)
47+
int(8)

Zend/zend_ast.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,8 +1575,7 @@ static ZEND_COLD void zend_ast_export_ex(smart_str *str, zend_ast *ast, int prio
15751575
zend_ast_export_type(str, decl->child[3], indent);
15761576
}
15771577
if (decl->child[2]) {
1578-
if (decl->kind == ZEND_AST_ARROW_FUNC) {
1579-
ZEND_ASSERT(decl->child[2]->kind == ZEND_AST_RETURN);
1578+
if (decl->kind == ZEND_AST_ARROW_FUNC && decl->child[2]->kind == ZEND_AST_RETURN) {
15801579
smart_str_appends(str, " => ");
15811580
zend_ast_export_ex(str, decl->child[2]->child[0], 0, indent);
15821581
break;

Zend/zend_language_parser.y

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,12 @@ inline_function:
11771177
zend_ast_create(ZEND_AST_RETURN, $11), $7, NULL);
11781178
((zend_ast_decl *) $$)->lex_pos = $10;
11791179
CG(extra_fn_flags) = $9; }
1180+
| fn returns_ref backup_doc_comment '(' parameter_list ')' return_type
1181+
T_DOUBLE_ARROW backup_fn_flags '{' inner_statement_list '}' backup_fn_flags
1182+
{ $$ = zend_ast_create_decl(ZEND_AST_ARROW_FUNC, $2 | $13, $1, $3,
1183+
zend_string_init("{closure}", sizeof("{closure}") - 1, 0), $5, NULL,
1184+
$11, $7, NULL);
1185+
CG(extra_fn_flags) = $9; }
11801186
;
11811187

11821188
fn:

0 commit comments

Comments
 (0)