Skip to content

Commit 51582bf

Browse files
committed
Allow for [] = $array; (alias for list())
1 parent 9af7ad0 commit 51582bf

File tree

8 files changed

+116
-78
lines changed

8 files changed

+116
-78
lines changed

Zend/tests/assert/expect_015.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ Warning: assert(): assert(0 && ($a = function () {
154154
$x = $a ? $b : $c;
155155
$x = $a ?: $c;
156156
$x = $a ?? $b;
157-
list($a, $b, $c) = [1, 2 => 'x', 'z' => 'c'];
157+
[$a, $b, $c] = [1, 2 => 'x', 'z' => 'c'];
158158
@foo();
159159
$y = clone $x;
160160
yield 1 => 2;

Zend/tests/list_001.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55

66
list($a, list($b)) = array(new stdclass, array(new stdclass));
77
var_dump($a, $b);
8+
[$a, [$b]] = array(new stdclass, array(new stdclass));
9+
var_dump($a, $b);
810

911
?>
1012
--EXPECT--
1113
object(stdClass)#1 (0) {
1214
}
1315
object(stdClass)#2 (0) {
1416
}
17+
object(stdClass)#3 (0) {
18+
}
19+
object(stdClass)#4 (0) {
20+
}

Zend/tests/list_008.phpt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Assignment to invalid list() value
3+
--FILE--
4+
<?php
5+
6+
[42] = [1];
7+
8+
?>
9+
--EXPECTF--
10+
Fatal error: Assignments can only happen to writable values in %s on line %d

Zend/tests/list_mixed_keyed_unkeyed.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,4 @@ list($zero, 1 => $one, "foo" => $foo) = $contrivedKeyedAndUnkeyedArrayExample;
1313

1414
?>
1515
--EXPECTF--
16-
Parse error: syntax error, unexpected %s in %s on line %d
16+
Fatal error: Cannot mix keyed and unkeyed array entries in assignments in %s on line %d

Zend/zend_ast.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,11 +1099,6 @@ static void zend_ast_export_ex(smart_str *str, zend_ast *ast, int priority, int
10991099
simple_list:
11001100
zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
11011101
break;
1102-
case ZEND_AST_LIST:
1103-
smart_str_appends(str, "list(");
1104-
zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);
1105-
smart_str_appendc(str, ')');
1106-
break;
11071102
case ZEND_AST_ARRAY:
11081103
smart_str_appendc(str, '[');
11091104
zend_ast_export_list(str, (zend_ast_list*)ast, 1, 20, indent);

Zend/zend_ast.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ enum _zend_ast_kind {
4242

4343
/* list nodes */
4444
ZEND_AST_ARG_LIST = 1 << ZEND_AST_IS_LIST_SHIFT,
45-
ZEND_AST_LIST,
4645
ZEND_AST_ARRAY,
4746
ZEND_AST_ENCAPS_LIST,
4847
ZEND_AST_EXPR_LIST,

Zend/zend_compile.c

Lines changed: 77 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2577,13 +2577,13 @@ static void zend_separate_if_call_and_write(znode *node, zend_ast *ast, uint32_t
25772577

25782578
void zend_delayed_compile_var(znode *result, zend_ast *ast, uint32_t type);
25792579
void zend_compile_assign(znode *result, zend_ast *ast);
2580-
static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node);
2580+
static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style);
25812581

25822582
static inline void zend_emit_assign_znode(zend_ast *var_ast, znode *value_node) /* {{{ */
25832583
{
25842584
znode dummy_node;
2585-
if (var_ast->kind == ZEND_AST_LIST) {
2586-
zend_compile_list_assign(&dummy_node, var_ast, value_node);
2585+
if (var_ast->kind == ZEND_AST_ARRAY) {
2586+
zend_compile_list_assign(&dummy_node, var_ast, value_node, var_ast->attr);
25872587
} else {
25882588
zend_ast *assign_ast = zend_ast_create(ZEND_AST_ASSIGN, var_ast,
25892589
zend_ast_create_znode(value_node));
@@ -2727,18 +2727,35 @@ void zend_compile_static_prop(znode *result, zend_ast *ast, uint32_t type, int d
27272727
}
27282728
/* }}} */
27292729

2730-
static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */
2730+
static void zend_verify_list_assign_target(zend_ast *var_ast, zend_bool old_style) /* {{{ */ {
2731+
if (var_ast->kind == ZEND_AST_ARRAY) {
2732+
if (old_style != var_ast->attr) {
2733+
zend_error(E_COMPILE_ERROR, "Cannot mix [] and list()");
2734+
}
2735+
} else if (!zend_can_write_to_variable(var_ast)) {
2736+
zend_error(E_COMPILE_ERROR, "Assignments can only happen to writable values");
2737+
}
2738+
}
2739+
/* }}} */
2740+
2741+
static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_node, zend_bool old_style) /* {{{ */
27312742
{
27322743
uint32_t i;
27332744
zend_bool has_elems = 0;
27342745

27352746
for (i = 0; i < list->children; ++i) {
2736-
zend_ast *var_ast = list->child[i];
2747+
zend_ast *elem_ast = list->child[i];
2748+
zend_ast *var_ast;
27372749
znode fetch_result, dim_node;
27382750

2739-
if (var_ast == NULL) {
2751+
if (elem_ast == NULL) {
27402752
continue;
27412753
}
2754+
if (elem_ast->attr) {
2755+
zend_error(E_COMPILE_ERROR, "[] and list() assignments cannot be by reference");
2756+
}
2757+
2758+
var_ast = elem_ast->child[0];
27422759
has_elems = 1;
27432760

27442761
dim_node.op_type = IS_CONST;
@@ -2748,6 +2765,12 @@ static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_no
27482765
Z_TRY_ADDREF(expr_node->u.constant);
27492766
}
27502767

2768+
if (elem_ast->child[1] != NULL) {
2769+
zend_error(E_COMPILE_ERROR, "Cannot mix keyed and unkeyed array entries in assignments");
2770+
}
2771+
2772+
zend_verify_list_assign_target(var_ast, old_style);
2773+
27512774
zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node);
27522775
zend_emit_assign_znode(var_ast, &fetch_result);
27532776
}
@@ -2758,7 +2781,7 @@ static void zend_compile_unkeyed_list_assign(zend_ast_list *list, znode *expr_no
27582781
}
27592782
/* }}} */
27602783

2761-
static void zend_compile_keyed_list_assign(zend_ast_list *list, znode *expr_node) /* {{{ */
2784+
static void zend_compile_keyed_list_assign(zend_ast_list *list, znode *expr_node, zend_bool old_style) /* {{{ */
27622785
{
27632786
uint32_t i;
27642787

@@ -2768,26 +2791,40 @@ static void zend_compile_keyed_list_assign(zend_ast_list *list, znode *expr_node
27682791
zend_ast *key_ast = pair_ast->child[1];
27692792
znode fetch_result, dim_node;
27702793

2794+
if (pair_ast->attr) {
2795+
zend_error(E_COMPILE_ERROR, "[] and list() assignments cannot be by reference");
2796+
}
2797+
27712798
zend_compile_expr(&dim_node, key_ast);
27722799

27732800
if (expr_node->op_type == IS_CONST) {
27742801
Z_TRY_ADDREF(expr_node->u.constant);
27752802
}
27762803

2804+
if (var_ast == NULL) {
2805+
zend_error(E_COMPILE_ERROR, "Cannot use empty array entries in keyed array");
2806+
}
2807+
2808+
if (key_ast == NULL) {
2809+
zend_error(E_COMPILE_ERROR, "Cannot mix keyed and unkeyed array entries in assignments");
2810+
}
2811+
2812+
zend_verify_list_assign_target(var_ast, old_style);
2813+
27772814
zend_emit_op(&fetch_result, ZEND_FETCH_LIST, expr_node, &dim_node);
27782815
zend_emit_assign_znode(var_ast, &fetch_result);
27792816
}
27802817
}
27812818
/* }}} */
27822819

2783-
static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node) /* {{{ */
2820+
static void zend_compile_list_assign(znode *result, zend_ast *ast, znode *expr_node, zend_bool old_style) /* {{{ */
27842821
{
27852822
zend_ast_list *list = zend_ast_get_list(ast);
27862823

2787-
if (list->children > 0 && list->child[0] != NULL && list->child[0]->kind == ZEND_AST_ARRAY_ELEM) {
2788-
zend_compile_keyed_list_assign(list, expr_node);
2824+
if (list->children > 0 && list->child[0] != NULL && list->child[0]->child[1] != NULL /* has key */) {
2825+
zend_compile_keyed_list_assign(list, expr_node, old_style);
27892826
} else {
2790-
zend_compile_unkeyed_list_assign(list, expr_node);
2827+
zend_compile_unkeyed_list_assign(list, expr_node, old_style);
27912828
}
27922829

27932830
*result = *expr_node;
@@ -2837,13 +2874,16 @@ zend_bool zend_list_has_assign_to(zend_ast *list_ast, zend_string *name) /* {{{
28372874
zend_ast_list *list = zend_ast_get_list(list_ast);
28382875
uint32_t i;
28392876
for (i = 0; i < list->children; i++) {
2840-
zend_ast *var_ast = list->child[i];
2841-
if (!var_ast) {
2877+
zend_ast *elem_ast = list->child[i];
2878+
zend_ast *var_ast;
2879+
2880+
if (!elem_ast) {
28422881
continue;
28432882
}
2883+
var_ast = elem_ast->child[0];
28442884

28452885
/* Recursively check nested list()s */
2846-
if (var_ast->kind == ZEND_AST_LIST && zend_list_has_assign_to(var_ast, name)) {
2886+
if (var_ast->kind == ZEND_AST_ARRAY && zend_list_has_assign_to(var_ast, name)) {
28472887
return 1;
28482888
}
28492889

@@ -2925,15 +2965,15 @@ void zend_compile_assign(znode *result, zend_ast *ast) /* {{{ */
29252965

29262966
zend_emit_op_data(&expr_node);
29272967
return;
2928-
case ZEND_AST_LIST:
2968+
case ZEND_AST_ARRAY:
29292969
if (zend_list_has_assign_to_self(var_ast, expr_ast)) {
29302970
/* list($a, $b) = $a should evaluate the right $a first */
29312971
zend_compile_simple_var_no_cv(&expr_node, expr_ast, BP_VAR_R, 0);
29322972
} else {
29332973
zend_compile_expr(&expr_node, expr_ast);
29342974
}
29352975

2936-
zend_compile_list_assign(result, var_ast, &expr_node);
2976+
zend_compile_list_assign(result, var_ast, &expr_node, var_ast->attr);
29372977
return;
29382978
EMPTY_SWITCH_DEFAULT_CASE();
29392979
}
@@ -4340,7 +4380,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */
43404380
if (key_ast->kind == ZEND_AST_REF) {
43414381
zend_error_noreturn(E_COMPILE_ERROR, "Key element cannot be a reference");
43424382
}
4343-
if (key_ast->kind == ZEND_AST_LIST) {
4383+
if (key_ast->kind == ZEND_AST_ARRAY) {
43444384
zend_error_noreturn(E_COMPILE_ERROR, "Cannot use list as key element");
43454385
}
43464386
}
@@ -6357,14 +6397,22 @@ static zend_bool zend_try_ct_eval_array(zval *result, zend_ast *ast) /* {{{ */
63576397
uint32_t i;
63586398
zend_bool is_constant = 1;
63596399

6400+
if (ast->attr) {
6401+
zend_error(E_COMPILE_ERROR, "Cannot use list() as standalone expression");
6402+
}
6403+
63606404
/* First ensure that *all* child nodes are constant and by-val */
63616405
for (i = 0; i < list->children; ++i) {
63626406
zend_ast *elem_ast = list->child[i];
6363-
zend_bool by_ref = elem_ast->attr;
6407+
6408+
if (elem_ast == NULL) {
6409+
zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
6410+
}
6411+
63646412
zend_eval_const_expr(&elem_ast->child[0]);
63656413
zend_eval_const_expr(&elem_ast->child[1]);
63666414

6367-
if (by_ref || elem_ast->child[0]->kind != ZEND_AST_ZVAL
6415+
if (elem_ast->attr /* by_ref */ || elem_ast->child[0]->kind != ZEND_AST_ZVAL
63686416
|| (elem_ast->child[1] && elem_ast->child[1]->kind != ZEND_AST_ZVAL)
63696417
) {
63706418
is_constant = 0;
@@ -6982,9 +7030,16 @@ void zend_compile_array(znode *result, zend_ast *ast) /* {{{ */
69827030

69837031
for (i = 0; i < list->children; ++i) {
69847032
zend_ast *elem_ast = list->child[i];
6985-
zend_ast *value_ast = elem_ast->child[0];
6986-
zend_ast *key_ast = elem_ast->child[1];
6987-
zend_bool by_ref = elem_ast->attr;
7033+
zend_ast *value_ast, *key_ast;
7034+
zend_bool by_ref;
7035+
7036+
if (elem_ast == NULL) {
7037+
zend_error(E_COMPILE_ERROR, "Cannot use empty array elements in arrays");
7038+
}
7039+
7040+
value_ast = elem_ast->child[0];
7041+
key_ast = elem_ast->child[1];
7042+
by_ref = elem_ast->attr;
69887043

69897044
znode value_node, key_node, *key_node_ptr = NULL;
69907045

0 commit comments

Comments
 (0)