diff --git a/spec/10-expressions.md b/spec/10-expressions.md
index 55863ba7..12ab39f3 100644
--- a/spec/10-expressions.md
+++ b/spec/10-expressions.md
@@ -414,9 +414,17 @@ isset($v1, $v2, $v3); // results in FALSE
list ( list-expression-listopt )
list-expression-list:
+ unkeyed-list-expression-list
+ keyed-list-expression-list ,opt
+
+ unkeyed-list-expression-list:
list-or-variable
,
- list-expression-list , list-or-variableopt
+ unkeyed-list-expression-list , list-or-variableopt
+
+ keyed-list-expression-list:
+ expression => list-or-variable
+ keyed-list-expression-list , expression => list-or-variable
list-or-variable:
list-intrinsic
@@ -446,7 +454,8 @@ target variables. On success, it returns a copy of the source array. If the
source array is not an array or object implementing `ArrayAccess` no
assignments are performed and the return value is `NULL`.
-All elements in the source array having keys of type `string` are ignored.
+For *unkeyed-list-expression-list*, all elements in the source array having
+keys of type `string` are ignored.
The element having an `int` key of 0 is assigned to the first target
variable, the element having an `int` key of 1 is assigned to the second
target variable, and so on, until all target variables have been
@@ -455,6 +464,15 @@ fewer source array elements having int keys than there are target
variables, the unassigned target variables are set to `NULL` and
a non-fatal error is produced.
+For *keyed-list-expression-list*, each key-variable pair is handled in turn,
+with the key and variable being separated by the `=>` symbol.
+The element having the first key, with the key having been converted using the
+same rules as the [subscript operator](10-expressions.md#subscript-operator),
+is assigned to the frst target variable. This process is repeated for the
+second `=>` pair, if any, and so on. Any other array elements are ignored.
+If there is no array element with a given key, the unassigned target variable
+is set to `NULL` and a non-fatal error is produced.
+
The assignments must occur in this order.
Any target variable may be a list, in which case, the corresponding
@@ -481,6 +499,24 @@ list($arr[1], $arr[0]) = [0, 1];
// $arr is [1 => 0, 0 => 1], in this order
list($arr2[], $arr2[]) = [0, 1];
// $arr2 is [0, 1]
+
+list("one" => $one, "two" => $two) = ["one" => 1, "two" => 2];
+ // $one is 1, $two is 2
+list(
+ "one" => $one,
+ "two" => $two,
+) = [
+ "one" => 1,
+ "two" => 2,
+];
+ // $one is 1, $two is 2
+list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = [
+ ["x" => 1, "y" => 2],
+ ["x" => 3, "y" => 4]
+];
+ // $x1 is 1, $y1 is 2, $x2 is 3, $y2 is 4
+list(0 => list($x1, $x2), 1 => list($x2, $y2)) = [[1, 2], [3, 4]];
+ // $x1 is 1, $y1 is 2, $x2 is 3, $y2 is 4
```
####print
diff --git a/spec/19-grammar.md b/spec/19-grammar.md
index bb1f77eb..f7fa7249 100644
--- a/spec/19-grammar.md
+++ b/spec/19-grammar.md
@@ -426,9 +426,17 @@ The grammar notation is described in [Grammars section](09-lexical-structure.md#
list ( list-expression-listopt )
list-expression-list:
+ unkeyed-list-expression-list
+ keyed-list-expression-list ,opt
+
+ unkeyed-list-expression-list:
list-or-variable
,
- list-expression-list , list-or-variableopt
+ unkeyed-list-expression-list , list-or-variableopt
+
+ keyed-list-expression-list:
+ expression => list-or-variable
+ keyed-list-expression-list , expression => list-or-variable
list-or-variable:
list-intrinsic
diff --git a/tests/expressions/list/list_001.phpt b/tests/expressions/list/list_001.phpt
new file mode 100644
index 00000000..a9fff550
--- /dev/null
+++ b/tests/expressions/list/list_001.phpt
@@ -0,0 +1,14 @@
+--TEST--
+"Nested" list()
+--FILE--
+
+--EXPECT--
+object(stdClass)#1 (0) {
+}
+object(stdClass)#2 (0) {
+}
diff --git a/tests/expressions/list/list_002.phpt b/tests/expressions/list/list_002.phpt
new file mode 100644
index 00000000..ac0d8974
--- /dev/null
+++ b/tests/expressions/list/list_002.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Testing full-reference on list()
+--FILE--
+
+--EXPECT--
+object(stdClass)#1 (0) {
+}
+object(stdClass)#1 (0) {
+}
+bool(true)
diff --git a/tests/expressions/list/list_003.phpt b/tests/expressions/list/list_003.phpt
new file mode 100644
index 00000000..4a509f6a
--- /dev/null
+++ b/tests/expressions/list/list_003.phpt
@@ -0,0 +1,24 @@
+--TEST--
+list() with non-array
+--FILE--
+
+--EXPECT--
+NULL
+NULL
+NULL
+NULL
+NULL
diff --git a/tests/expressions/list/list_004.phpt b/tests/expressions/list/list_004.phpt
new file mode 100644
index 00000000..862a4e43
--- /dev/null
+++ b/tests/expressions/list/list_004.phpt
@@ -0,0 +1,21 @@
+--TEST--
+list() with array reference
+--FILE--
+
+--EXPECT--
+int(1)
+array(2) {
+ [0]=>
+ int(2)
+ [1]=>
+ int(1)
+}
diff --git a/tests/expressions/list/list_005.phpt b/tests/expressions/list/list_005.phpt
new file mode 100644
index 00000000..7dc3bf6f
--- /dev/null
+++ b/tests/expressions/list/list_005.phpt
@@ -0,0 +1,50 @@
+--TEST--
+Testing list() with several variables
+--FILE--
+
+--EXPECTF--
+NULL
+NULL
+NULL
+----
+NULL
+NULL
+NULL
+----
+
+Fatal error: Uncaught Error: Cannot use object of type stdClass as array in %s:%d
+Stack trace:
+#0 {main}
+ thrown in %s on line %d
diff --git a/tests/expressions/list/list_006.phpt b/tests/expressions/list/list_006.phpt
new file mode 100644
index 00000000..d380235d
--- /dev/null
+++ b/tests/expressions/list/list_006.phpt
@@ -0,0 +1,12 @@
+--TEST--
+Testing nested list() with empty array
+--FILE--
+
+--EXPECTF--
+Notice: Undefined offset: 0 in %s on line %d
+
+Notice: Undefined offset: 1 in %s on line %d
diff --git a/tests/expressions/list/list_007.phpt b/tests/expressions/list/list_007.phpt
new file mode 100644
index 00000000..67c65245
--- /dev/null
+++ b/tests/expressions/list/list_007.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Using lambda with list()
+--FILE--
+
+--EXPECTF--
+Fatal error: Uncaught Error: Cannot use object of type Closure as array in %slist_007.php:3
+Stack trace:
+#0 {main}
+ thrown in %slist_007.php on line 3
diff --git a/tests/expressions/list/list_destructuring_to_special_variables.phpt b/tests/expressions/list/list_destructuring_to_special_variables.phpt
new file mode 100644
index 00000000..4418c967
--- /dev/null
+++ b/tests/expressions/list/list_destructuring_to_special_variables.phpt
@@ -0,0 +1,49 @@
+--TEST--
+list() can be used to destructure to string offsets, __set and ArrayAccess::offsetSet
+--FILE--
+values[$name] = $value;
+ }
+}
+
+class Arr implements ArrayAccess {
+ public $values = [];
+ public function offsetSet($name, $value) {
+ $this->values[$name] = $value;
+ }
+ public function offsetGet($name) {}
+ public function offsetExists($name) {}
+ public function offsetUnset($name) {}
+}
+
+$str = 'ab';
+list($str[0], $str[1]) = ['x', 'y'];
+var_dump($str);
+
+$obj = new Obj;
+list($obj->foo, $obj->bar) = ['foo', 'bar'];
+var_dump($obj->values);
+
+$arr = new Arr;
+list($arr['foo'], $arr['bar']) = ['foo', 'bar'];
+var_dump($arr->values);
+
+?>
+--EXPECT--
+string(2) "xy"
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
+array(2) {
+ ["foo"]=>
+ string(3) "foo"
+ ["bar"]=>
+ string(3) "bar"
+}
diff --git a/tests/expressions/list/list_empty_error.phpt b/tests/expressions/list/list_empty_error.phpt
new file mode 100644
index 00000000..78de2e95
--- /dev/null
+++ b/tests/expressions/list/list_empty_error.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Empty list() assignments are not allowed
+--FILE--
+
+--EXPECTF--
+Fatal error: Cannot use empty list in %s on line %d
diff --git a/tests/expressions/list/list_keyed.phpt b/tests/expressions/list/list_keyed.phpt
new file mode 100644
index 00000000..b549ed9b
--- /dev/null
+++ b/tests/expressions/list/list_keyed.phpt
@@ -0,0 +1,71 @@
+--TEST--
+list() with keys
+--FILE--
+ "bad",
+ "happy" => "sad",
+];
+
+list("good" => $good_antonym, "happy" => $happy_antonym) = $antonyms;
+var_dump($good_antonym, $happy_antonym);
+
+echo PHP_EOL;
+
+$powersOfTwo = [
+ 1 => 2,
+ 2 => 4,
+ 3 => 8
+];
+
+list(1 => $two_1, 2 => $two_2, 3 => $two_3) = $powersOfTwo;
+var_dump($two_1, $two_2, $two_3);
+
+echo PHP_EOL;
+
+$contrivedMixedKeyTypesExample = [
+ 7 => "the best PHP version",
+ "elePHPant" => "the cutest mascot"
+];
+
+list(7 => $seven, "elePHPant" => $elePHPant) = $contrivedMixedKeyTypesExample;
+var_dump($seven, $elePHPant);
+
+echo PHP_EOL;
+
+$allTogetherNow = [
+ "antonyms" => $antonyms,
+ "powersOfTwo" => $powersOfTwo,
+ "contrivedMixedKeyTypesExample" => $contrivedMixedKeyTypesExample
+];
+
+list(
+ "antonyms" => list("good" => $good_antonym, "happy" => $happy_antonym),
+ "powersOfTwo" => list(1 => $two_1, 2 => $two_2, 3 => $two_3),
+ "contrivedMixedKeyTypesExample" => list(7 => $seven, "elePHPant" => $elePHPant)
+) = $allTogetherNow;
+
+var_dump($good_antonym, $happy_antonym);
+var_dump($two_1, $two_2, $two_3);
+var_dump($seven, $elePHPant);
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+int(2)
+int(4)
+int(8)
+
+string(20) "the best PHP version"
+string(17) "the cutest mascot"
+
+string(3) "bad"
+string(3) "sad"
+int(2)
+int(4)
+int(8)
+string(20) "the best PHP version"
+string(17) "the cutest mascot"
diff --git a/tests/expressions/list/list_keyed_ArrayAccess.phpt b/tests/expressions/list/list_keyed_ArrayAccess.phpt
new file mode 100644
index 00000000..1bb20130
--- /dev/null
+++ b/tests/expressions/list/list_keyed_ArrayAccess.phpt
@@ -0,0 +1,54 @@
+--TEST--
+list() with keys and ArrayAccess
+--FILE--
+ $good, "happy" => $happy) = $antonymObject;
+var_dump($good, $happy);
+
+echo PHP_EOL;
+
+$stdClassCollection = new SplObjectStorage;
+$foo = new StdClass;
+$stdClassCollection[$foo] = "foo";
+$bar = new StdClass;
+$stdClassCollection[$bar] = "bar";
+
+list($foo => $fooStr, $bar => $barStr) = $stdClassCollection;
+var_dump($fooStr, $barStr);
+
+echo PHP_EOL;
+
+class IndexPrinter implements ArrayAccess
+{
+ public function offsetGet($offset) {
+ echo "GET ";
+ var_dump($offset);
+ }
+ public function offsetSet($offset, $value) {
+ }
+ public function offsetExists($offset) {
+ }
+ public function offsetUnset($offset) {
+ }
+}
+
+$op = new IndexPrinter;
+list(123 => $x) = $op;
+// PHP shouldn't convert this to an integer offset, because it's ArrayAccess
+list("123" => $x) = $op;
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+string(3) "foo"
+string(3) "bar"
+
+GET int(123)
+GET string(3) "123"
diff --git a/tests/expressions/list/list_keyed_conversions.phpt b/tests/expressions/list/list_keyed_conversions.phpt
new file mode 100644
index 00000000..e2cf91a2
--- /dev/null
+++ b/tests/expressions/list/list_keyed_conversions.phpt
@@ -0,0 +1,32 @@
+--TEST--
+list() with non-integer-or-string keys
+--FILE--
+ 0,
+ 1 => 1,
+ "" => ""
+];
+
+list(NULL => $NULL, 1.5 => $float, FALSE => $FALSE, TRUE => $TRUE) = $results;
+var_dump($NULL, $float, $FALSE, $TRUE);
+
+echo PHP_EOL;
+
+list("0" => $zeroString, "1" => $oneString) = $results;
+var_dump($zeroString, $oneString);
+
+list(STDIN => $resource) = [];
+
+?>
+--EXPECTF--
+string(0) ""
+int(1)
+int(0)
+int(1)
+
+int(0)
+int(1)
+
+Notice: Resource ID#%d used as offset, casting to integer (%d) in %s on line %d
diff --git a/tests/expressions/list/list_keyed_evaluation_order.inc b/tests/expressions/list/list_keyed_evaluation_order.inc
new file mode 100644
index 00000000..490a6d84
--- /dev/null
+++ b/tests/expressions/list/list_keyed_evaluation_order.inc
@@ -0,0 +1,60 @@
+name = $name;
+ }
+
+ public function __toString(): string {
+ echo "$this->name evaluated.", PHP_EOL;
+ return $this->name;
+ }
+}
+
+class Indexable implements ArrayAccess
+{
+ private $array;
+ public function __construct(array $array) {
+ $this->array = $array;
+ }
+
+ public function offsetExists($offset): bool {
+ echo "Existence of offset $offset checked for.", PHP_EOL;
+ return isset($this->array[$offset]);
+ }
+
+ public function offsetUnset($offset): void {
+ unset($this->array[$offset]);
+ echo "Offset $offset removed.", PHP_EOL;
+ }
+
+ public function offsetGet($offset) {
+ echo "Offset $offset retrieved.", PHP_EOL;
+ return $this->array[$offset];
+ }
+
+ public function offsetSet($offset, $value): void {
+ $this->array[$offset] = $value;
+ echo "Offset $offset set to $value.", PHP_EOL;
+ }
+}
+
+class IndexableRetrievable
+{
+ private $label;
+ private $indexable;
+
+ public function __construct(string $label, Indexable $indexable) {
+ $this->label = $label;
+ $this->indexable = $indexable;
+ }
+
+ public function getIndexable(): Indexable {
+ echo "Indexable $this->label retrieved.", PHP_EOL;
+ return $this->indexable;
+ }
+}
diff --git a/tests/expressions/list/list_keyed_evaluation_order.phpt b/tests/expressions/list/list_keyed_evaluation_order.phpt
new file mode 100644
index 00000000..0f0652b6
--- /dev/null
+++ b/tests/expressions/list/list_keyed_evaluation_order.phpt
@@ -0,0 +1,35 @@
+--TEST--
+list() with keys, evaluation order
+--FILE--
+ "value for offset A", "C" => "value for offset C"]));
+
+$store = new Indexable([]);
+
+// list($a => $b, $c => $d) = $e;
+// Should be evaluated in the order:
+// 1. Evaluate $e
+// 2. Evaluate $a
+// 3. Evaluate $e[$a]
+// 4. Assign $b from $e[$a]
+// 5. Evaluate $c
+// 6. Evaluate $e[$c]
+// 7. Assign $c from $e[$a]
+
+list((string)$a => $store["B"], (string)$c => $store["D"]) = $e->getIndexable();
+
+?>
+--EXPECT--
+Indexable E retrieved.
+A evaluated.
+Offset A retrieved.
+Offset B set to value for offset A.
+C evaluated.
+Offset C retrieved.
+Offset D set to value for offset C.
diff --git a/tests/expressions/list/list_keyed_evaluation_order_2.phpt b/tests/expressions/list/list_keyed_evaluation_order_2.phpt
new file mode 100644
index 00000000..ddfba68c
--- /dev/null
+++ b/tests/expressions/list/list_keyed_evaluation_order_2.phpt
@@ -0,0 +1,77 @@
+--TEST--
+list() with keys, evaluation order #2
+--FILE--
+ $a, 1 => $b) = ['a', 'b'];
+var_dump($a);
+var_dump($b);
+
+list(1 => $b, 0 => $a) = ['a', 'b'];
+var_dump($a);
+var_dump($b);
+
+$arr = [];
+list($arr[], $arr[]) = ['a', 'b'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(0 => $arr[], 1 => $arr[]) = ['a', 'b'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(1 => $arr[], 0 => $arr[]) = ['b', 'a'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list(list(1 => $arr[], 0 => $arr[])) = [['b', 'a']];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+$arr = [];
+list('key1' => $arr[], 'key2' => $arr[]) = ['key2' => 'b', 'key1' => 'a'];
+var_dump($arr[0]);
+var_dump($arr[1]);
+
+// This should print 'foo'
+$a = 0;
+list($a => $a) = ['foo', 'bar'];
+var_dump($a);
+
+// This should print 'bar' then 'foo'
+$a = 0;
+$b = 1;
+list($b => $a, $a => $c) = ['bar' => 'foo', 1 => 'bar'];
+var_dump($a);
+var_dump($c);
+
+?>
+--EXPECT--
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(1) "a"
+string(1) "b"
+string(3) "foo"
+string(3) "bar"
+string(3) "foo"
diff --git a/tests/expressions/list/list_keyed_evaluation_order_3.phpt b/tests/expressions/list/list_keyed_evaluation_order_3.phpt
new file mode 100644
index 00000000..7850834c
--- /dev/null
+++ b/tests/expressions/list/list_keyed_evaluation_order_3.phpt
@@ -0,0 +1,24 @@
+--TEST--
+list() with keys, evaluation order #3
+--FILE--
+ [
+ 'b' => 'bar',
+ 'a' => 'foo',
+ ],
+ 1 => 'a',
+ 3 => 'b',
+];
+list($a[$i++] => $a[$i++], $a[$i++] => $a[$i++]) = $a[$i++];
+var_dump($i); // should be 5
+var_dump($a[2]); // should be 'foo'
+var_dump($a[4]); // should be 'bar'
+
+?>
+--EXPECT--
+int(5)
+string(3) "foo"
+string(3) "bar"
diff --git a/tests/expressions/list/list_keyed_evaluation_order_nested.phpt b/tests/expressions/list/list_keyed_evaluation_order_nested.phpt
new file mode 100644
index 00000000..8a7725d4
--- /dev/null
+++ b/tests/expressions/list/list_keyed_evaluation_order_nested.phpt
@@ -0,0 +1,77 @@
+--TEST--
+list() with keys, evaluation order: nested
+--FILE--
+ "offset value for A",
+ "C" => new Indexable([
+ 0 => "offset value for 0",
+ 1 => "offset value for 1"
+ ]),
+ "F" => new Indexable([
+ "G" => "offset value for G",
+ "I" => "offset value for I"
+ ])
+]));
+
+$store = new Indexable([]);
+
+// list($a => $b, $c => list($d, $e), $f => list($g => $h, $i => $j)) = $k;
+// Should be evaluated in the order:
+// 1. Evaluate $k
+// 2. Evaluate $a
+// 3. Evaluate $k[$a]
+// 4. Assign $b from $k[$a]
+// 5. Evaluate $c
+// 6. Evaluate $k[$c]
+// 7. Evaluate $k[$c][0]
+// 8. Assign $d from $k[$c][0]
+// 9. Evaluate $k[$c][1]
+// 10. Assign $e from $k[$c][1]
+// 11. Evaluate $f
+// 12. Evaluate $k[$f]
+// 13. Evaluate $g
+// 14. Evaluate $k[$f][$g]
+// 15. Assign $h from $k[$f][$g]
+// 16. Evaluate $i
+// 17. Evaluate $k[$f][$i]
+// 18. Assign $j from $k[$f][$i]
+
+list(
+ (string)$a => $store["B"],
+ (string)$c => list($store["D"], $store["E"]),
+ (string)$f => list(
+ (string)$g => $store["H"],
+ (string)$i => $store["J"]
+ )
+) = $k->getIndexable();
+
+?>
+--EXPECT--
+Indexable K retrieved.
+A evaluated.
+Offset A retrieved.
+Offset B set to offset value for A.
+C evaluated.
+Offset C retrieved.
+Offset 0 retrieved.
+Offset D set to offset value for 0.
+Offset 1 retrieved.
+Offset E set to offset value for 1.
+F evaluated.
+Offset F retrieved.
+G evaluated.
+Offset G retrieved.
+Offset H set to offset value for G.
+I evaluated.
+Offset I retrieved.
+Offset J set to offset value for I.
diff --git a/tests/expressions/list/list_keyed_non_literals.phpt b/tests/expressions/list/list_keyed_non_literals.phpt
new file mode 100644
index 00000000..80f22eda
--- /dev/null
+++ b/tests/expressions/list/list_keyed_non_literals.phpt
@@ -0,0 +1,30 @@
+--TEST--
+list() with constant keys
+--FILE--
+ "one",
+ 2 => "two",
+ 3 => "three"
+];
+
+const COMPILE_TIME_RESOLVABLE = 1;
+
+define('PROBABLY_NOT_COMPILE_TIME_RESOLVABLE', file_get_contents("data:text/plain,2"));
+
+$probablyNotCompileTimeResolvable3 = cos(0) * 3;
+
+list(
+ COMPILE_TIME_RESOLVABLE => $one,
+ PROBABLY_NOT_COMPILE_TIME_RESOLVABLE => $two,
+ $probablyNotCompileTimeResolvable3 => $three
+) = $arr;
+
+var_dump($one, $two, $three);
+
+?>
+--EXPECTF--
+string(3) "one"
+string(3) "two"
+string(5) "three"
diff --git a/tests/expressions/list/list_keyed_trailing_comma.phpt b/tests/expressions/list/list_keyed_trailing_comma.phpt
new file mode 100644
index 00000000..e0af0aed
--- /dev/null
+++ b/tests/expressions/list/list_keyed_trailing_comma.phpt
@@ -0,0 +1,38 @@
+--TEST--
+list() with keys and a trailing comma
+--FILE--
+ "bad",
+ "happy" => "sad",
+];
+
+list(
+ "good" => $good,
+ "happy" => $happy
+) = $antonyms;
+
+var_dump($good, $happy);
+
+echo PHP_EOL;
+
+$antonyms = [
+ "good" => "bad",
+ "happy" => "sad",
+];
+
+list(
+ "good" => $good,
+ "happy" => $happy,
+) = $antonyms;
+
+var_dump($good, $happy);
+
+?>
+--EXPECT--
+string(3) "bad"
+string(3) "sad"
+
+string(3) "bad"
+string(3) "sad"
diff --git a/tests/expressions/list/list_keyed_undefined.phpt b/tests/expressions/list/list_keyed_undefined.phpt
new file mode 100644
index 00000000..a18e3b4d
--- /dev/null
+++ b/tests/expressions/list/list_keyed_undefined.phpt
@@ -0,0 +1,22 @@
+--TEST--
+list() with undefined keys
+--FILE--
+ "the best PHP version",
+ "elePHPant" => "the cutest mascot"
+];
+
+list(5 => $five, "duke" => $duke) = $contrivedMixedKeyTypesExample;
+
+var_dump($five, $duke);
+
+?>
+--EXPECTF--
+
+Notice: Undefined offset: 5 in %s on line %d
+
+Notice: Undefined index: duke in %s on line %d
+NULL
+NULL
diff --git a/tests/expressions/list/list_mixed_keyed_unkeyed.phpt b/tests/expressions/list/list_mixed_keyed_unkeyed.phpt
new file mode 100644
index 00000000..5562479f
--- /dev/null
+++ b/tests/expressions/list/list_mixed_keyed_unkeyed.phpt
@@ -0,0 +1,16 @@
+--TEST--
+list() with both keyed and unkeyed elements
+--FILE--
+ 1,
+ "foo" => "bar"
+];
+
+list($zero, 1 => $one, "foo" => $foo) = $contrivedKeyedAndUnkeyedArrayExample;
+
+?>
+--EXPECTF--
+Parse error: syntax error, unexpected %s in %s on line %d
diff --git a/tests/expressions/list/list_mixed_nested_keyed_unkeyed.phpt b/tests/expressions/list/list_mixed_nested_keyed_unkeyed.phpt
new file mode 100644
index 00000000..3087775b
--- /dev/null
+++ b/tests/expressions/list/list_mixed_nested_keyed_unkeyed.phpt
@@ -0,0 +1,34 @@
+--TEST--
+list() with nested unkeyed and keyed list()
+--FILE--
+ 1, "y" => 2],
+ ["x" => 2, "y" => 1]
+];
+
+list(list("x" => $x1, "y" => $y1), list("x" => $x2, "y" => $y2)) = $points;
+var_dump($x1, $y1, $x2, $y2);
+
+echo PHP_EOL;
+
+$invertedPoints = [
+ "x" => [1, 2],
+ "y" => [2, 1]
+];
+
+list("x" => list($x1, $x2), "y" => list($y1, $y2)) = $invertedPoints;
+var_dump($x1, $y1, $x2, $y2);
+
+?>
+--EXPECT--
+int(1)
+int(2)
+int(2)
+int(1)
+
+int(1)
+int(2)
+int(2)
+int(1)
diff --git a/tests/expressions/list/list_self_assign.phpt b/tests/expressions/list/list_self_assign.phpt
new file mode 100644
index 00000000..46409126
--- /dev/null
+++ b/tests/expressions/list/list_self_assign.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Test variable occuring on both LHS and RHS of list()
+--FILE--
+
+--EXPECT--
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)
+int(1)
+int(2)
+int(3)