bazel syntax: rename ListLiteral to ListExpression A literal is a value provided in the syntax tree. By contrast, a list expression involves computation (of its elements) and may fail. Also: - remove enum Kind. A boolean is fine. - update comments and doc strings. A follow-up will do the same for DictionaryLiteral. PiperOrigin-RevId: 269366336
diff --git a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java index 726c512..7acd90b 100644 --- a/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java +++ b/src/main/java/com/google/devtools/build/lib/packages/PackageFactory.java
@@ -59,7 +59,7 @@ import com.google.devtools.build.lib.syntax.Identifier; import com.google.devtools.build.lib.syntax.IfStatement; import com.google.devtools.build.lib.syntax.IntegerLiteral; -import com.google.devtools.build.lib.syntax.ListLiteral; +import com.google.devtools.build.lib.syntax.ListExpression; import com.google.devtools.build.lib.syntax.Mutability; import com.google.devtools.build.lib.syntax.Node; import com.google.devtools.build.lib.syntax.NodeVisitor; @@ -1850,8 +1850,8 @@ continue; } if (arg.getIdentifier() == null || arg.getIdentifier().getName().equals("include")) { - if (arg.getValue() instanceof ListLiteral) { - ListLiteral list = (ListLiteral) arg.getValue(); + if (arg.getValue() instanceof ListExpression) { + ListExpression list = (ListExpression) arg.getValue(); for (Expression elem : list.getElements()) { if (elem instanceof StringLiteral) { globStrings.add(((StringLiteral) elem).getValue());
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java index cd518e9..64d71ba 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/AssignmentStatement.java
@@ -19,7 +19,7 @@ /** Syntax node for an assignment statement. */ public final class AssignmentStatement extends Statement { - private final Expression lhs; // = IDENTIFIER | DOT | INDEX | LIST_LITERAL + private final Expression lhs; // = IDENTIFIER | DOT | INDEX | LIST_EXPR private final Expression rhs; /**
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Eval.java b/src/main/java/com/google/devtools/build/lib/syntax/Eval.java index 37e45a3..c68e2a8 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Eval.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Eval.java
@@ -245,8 +245,8 @@ Object object = ((IndexExpression) expr).getObject().eval(env); Object key = ((IndexExpression) expr).getKey().eval(env); assignItem(object, key, value, env, loc); - } else if (expr instanceof ListLiteral) { - ListLiteral list = (ListLiteral) expr; + } else if (expr instanceof ListExpression) { + ListExpression list = (ListExpression) expr; assignList(list, value, env, loc); } else { // Not possible for validated ASTs. @@ -287,12 +287,12 @@ } /** - * Recursively assigns an iterable value to a list literal. + * Recursively assigns an iterable value to a sequence of assignable expressions. * * @throws EvalException if the list literal has length 0, or if the value is not an iterable of * matching length */ - private static void assignList(ListLiteral list, Object value, Environment env, Location loc) + private static void assignList(ListExpression list, Object value, Environment env, Location loc) throws EvalException, InterruptedException { Collection<?> collection = EvalUtils.toCollection(value, loc, env); int len = list.getElements().size(); @@ -341,7 +341,7 @@ Object rhsValue = rhs.eval(env); Object result = BinaryOperatorExpression.evaluateAugmented(op, oldValue, rhsValue, env, loc); assignItem(object, key, result, env, loc); - } else if (expr instanceof ListLiteral) { + } else if (expr instanceof ListExpression) { throw new EvalException(loc, "cannot perform augmented assignment on a list literal"); } else { // Not possible for validated ASTs.
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Expression.java b/src/main/java/com/google/devtools/build/lib/syntax/Expression.java index ef7f3de..76256e1 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Expression.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Expression.java
@@ -41,7 +41,7 @@ IDENTIFIER, INDEX, INTEGER_LITERAL, - LIST_LITERAL, + LIST_EXPR, SLICE, STRING_LITERAL, UNARY_OPERATOR,
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Identifier.java b/src/main/java/com/google/devtools/build/lib/syntax/Identifier.java index 325fbf4..457ad19 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Identifier.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Identifier.java
@@ -200,8 +200,8 @@ result.add((Identifier) lhs); return; } - if (lhs instanceof ListLiteral) { - ListLiteral variables = (ListLiteral) lhs; + if (lhs instanceof ListExpression) { + ListExpression variables = (ListExpression) lhs; for (Expression expression : variables.getElements()) { collectBoundIdentifiers(expression, result); }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java b/src/main/java/com/google/devtools/build/lib/syntax/ListExpression.java similarity index 73% rename from src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java rename to src/main/java/com/google/devtools/build/lib/syntax/ListExpression.java index b99e11f..371fafc 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/ListLiteral.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/ListExpression.java
@@ -19,46 +19,25 @@ import java.util.ArrayList; import java.util.List; -/** - * Syntax node for list and tuple literals. - * - * <p>(Note that during evaluation, both list and tuple values are represented by java.util.List - * objects, the only difference between them being whether or not they are mutable.) - */ -// TODO(adonovan): rename ListExpression. -public final class ListLiteral extends Expression { +/** Syntax node for list and tuple expressions. */ +public final class ListExpression extends Expression { - /** Types of the ListLiteral. */ - // TODO(laurentlb): This conflicts with Expression.Kind, maybe remove it? // TODO(adonovan): split class into {List,Tuple}Expression, as a tuple may have no parens. - // (Do this after we materialize ParenExpressions.) - public enum Kind { - LIST, - TUPLE - } - - private final Kind kind; - + private final boolean isTuple; private final List<Expression> elements; - ListLiteral(Kind kind, List<Expression> elements) { - this.kind = kind; + ListExpression(boolean isTuple, List<Expression> elements) { + this.isTuple = isTuple; this.elements = elements; } - public Kind getKind() { - return kind; - } - public List<Expression> getElements() { return elements; } - /** - * Returns true if this list is a tuple (a hash table, immutable list). - */ + /** Reports whether this is a tuple expression. */ public boolean isTuple() { - return kind == Kind.TUPLE; + return isTuple; } @Override @@ -105,6 +84,6 @@ @Override public Expression.Kind kind() { - return Expression.Kind.LIST_LITERAL; + return Expression.Kind.LIST_EXPR; } }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/NodeVisitor.java b/src/main/java/com/google/devtools/build/lib/syntax/NodeVisitor.java index 2af1ea8..ed51b34 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/NodeVisitor.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/NodeVisitor.java
@@ -97,7 +97,7 @@ } } - public void visit(ListLiteral node) { + public void visit(ListExpression node) { visitAll(node.getElements()); }
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java index a58b5c7..5986408 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/Parser.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/Parser.java
@@ -288,7 +288,7 @@ List<Expression> tuple = parseExprList(insideParens); tuple.add(0, expression); // add the first expression to the front of the tuple return setLocation( - new ListLiteral(ListLiteral.Kind.TUPLE, tuple), start, Iterables.getLast(tuple)); + new ListExpression(/*isTuple=*/ true, tuple), start, Iterables.getLast(tuple)); } private void reportError(Location location, String message) { @@ -637,7 +637,7 @@ nextToken(); // check for the empty tuple literal if (token.kind == TokenKind.RPAREN) { - ListLiteral tuple = new ListLiteral(ListLiteral.Kind.TUPLE, ImmutableList.of()); + ListExpression tuple = new ListExpression(/*isTuple=*/ true, ImmutableList.of()); setLocation(tuple, start, token.right); nextToken(); return tuple; @@ -768,7 +768,7 @@ tuple.add(parsePrimaryWithSuffix()); } return setLocation( - new ListLiteral(ListLiteral.Kind.TUPLE, tuple), start, Iterables.getLast(tuple)); + new ListExpression(/*isTuple=*/ true, tuple), start, Iterables.getLast(tuple)); } // comprehension_suffix ::= 'FOR' loop_variables 'IN' expr comprehension_suffix @@ -814,7 +814,7 @@ int start = token.left; expect(TokenKind.LBRACKET); if (token.kind == TokenKind.RBRACKET) { // empty List - ListLiteral list = new ListLiteral(ListLiteral.Kind.LIST, ImmutableList.of()); + ListExpression list = new ListExpression(/*isTuple=*/ false, ImmutableList.of()); setLocation(list, start, token.right); nextToken(); return list; @@ -825,7 +825,8 @@ switch (token.kind) { case RBRACKET: // singleton list { - ListLiteral list = new ListLiteral(ListLiteral.Kind.LIST, ImmutableList.of(expression)); + ListExpression list = + new ListExpression(/*isTuple=*/ false, ImmutableList.of(expression)); setLocation(list, start, token.right); nextToken(); return list; @@ -844,7 +845,7 @@ token.right); elems.add(0, expression); // TODO(adonovan): opt: don't do this if (token.kind == TokenKind.RBRACKET) { - ListLiteral list = new ListLiteral(ListLiteral.Kind.LIST, elems); + ListExpression list = new ListExpression(/*isTuple=*/ false, elems); setLocation(list, start, token.right); nextToken(); return list;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java index b1a0872..c0f4f31 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkList.java
@@ -207,23 +207,22 @@ * A Skylark list, i.e., the value represented by {@code [1, 2, 3]}. Lists are mutable datatypes. */ @SkylarkModule( - name = "list", - category = SkylarkModuleCategory.BUILTIN, - doc = - "A language built-in type to support lists. Example of list literal:<br>" - + "<pre class=language-python>x = [1, 2, 3]</pre>" - + "Accessing elements is possible using indexing (starts from <code>0</code>):<br>" - + "<pre class=language-python>e = x[1] # e == 2</pre>" - + "Lists support the <code>+</code> operator to concatenate two lists. Example:<br>" - + "<pre class=language-python>x = [1, 2] + [3, 4] # x == [1, 2, 3, 4]\n" - + "x = [\"a\", \"b\"]\n" - + "x += [\"c\"] # x == [\"a\", \"b\", \"c\"]</pre>" - + "Similar to strings, lists support slice operations:" - + "<pre class=language-python>['a', 'b', 'c', 'd'][1:3] # ['b', 'c']\n" - + "['a', 'b', 'c', 'd'][::2] # ['a', 'c']\n" - + "['a', 'b', 'c', 'd'][3:0:-1] # ['d', 'c', 'b']</pre>" - + "Lists are mutable, as in Python." - ) + name = "list", + category = SkylarkModuleCategory.BUILTIN, + doc = + "The built-in list type. Example list expressions:<br>" + + "<pre class=language-python>x = [1, 2, 3]</pre>" + + "Accessing elements is possible using indexing (starts from <code>0</code>):<br>" + + "<pre class=language-python>e = x[1] # e == 2</pre>" + + "Lists support the <code>+</code> operator to concatenate two lists. Example:<br>" + + "<pre class=language-python>x = [1, 2] + [3, 4] # x == [1, 2, 3, 4]\n" + + "x = [\"a\", \"b\"]\n" + + "x += [\"c\"] # x == [\"a\", \"b\", \"c\"]</pre>" + + "Similar to strings, lists support slice operations:" + + "<pre class=language-python>['a', 'b', 'c', 'd'][1:3] # ['b', 'c']\n" + + "['a', 'b', 'c', 'd'][::2] # ['a', 'c']\n" + + "['a', 'b', 'c', 'd'][3:0:-1] # ['d', 'c', 'b']</pre>" + + "Lists are mutable, as in Python.") public static final class MutableList<E> extends SkylarkList<E> { private final ArrayList<E> contents; @@ -604,23 +603,22 @@ * (regardless of the {@link Environment} they are created in). */ @SkylarkModule( - name = "tuple", - category = SkylarkModuleCategory.BUILTIN, - doc = - "A language built-in type to support tuples. Example of tuple literal:<br>" - + "<pre class=language-python>x = (1, 2, 3)</pre>" - + "Accessing elements is possible using indexing (starts from <code>0</code>):<br>" - + "<pre class=language-python>e = x[1] # e == 2</pre>" - + "Lists support the <code>+</code> operator to concatenate two tuples. Example:<br>" - + "<pre class=language-python>x = (1, 2) + (3, 4) # x == (1, 2, 3, 4)\n" - + "x = (\"a\", \"b\")\n" - + "x += (\"c\",) # x == (\"a\", \"b\", \"c\")</pre>" - + "Similar to lists, tuples support slice operations:" - + "<pre class=language-python>('a', 'b', 'c', 'd')[1:3] # ('b', 'c')\n" - + "('a', 'b', 'c', 'd')[::2] # ('a', 'c')\n" - + "('a', 'b', 'c', 'd')[3:0:-1] # ('d', 'c', 'b')</pre>" - + "Tuples are immutable, therefore <code>x[1] = \"a\"</code> is not supported." - ) + name = "tuple", + category = SkylarkModuleCategory.BUILTIN, + doc = + "The built-in tuple type. Example tuple expressions:<br>" + + "<pre class=language-python>x = (1, 2, 3)</pre>" + + "Accessing elements is possible using indexing (starts from <code>0</code>):<br>" + + "<pre class=language-python>e = x[1] # e == 2</pre>" + + "Lists support the <code>+</code> operator to concatenate two tuples. Example:<br>" + + "<pre class=language-python>x = (1, 2) + (3, 4) # x == (1, 2, 3, 4)\n" + + "x = (\"a\", \"b\")\n" + + "x += (\"c\",) # x == (\"a\", \"b\", \"c\")</pre>" + + "Similar to lists, tuples support slice operations:" + + "<pre class=language-python>('a', 'b', 'c', 'd')[1:3] # ('b', 'c')\n" + + "('a', 'b', 'c', 'd')[::2] # ('a', 'c')\n" + + "('a', 'b', 'c', 'd')[3:0:-1] # ('d', 'c', 'b')</pre>" + + "Tuples are immutable, therefore <code>x[1] = \"a\"</code> is not supported.") public static final class Tuple<E> extends SkylarkList<E> { private final ImmutableList<E> contents;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java index 2e25d08..47ad90b 100644 --- a/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java +++ b/src/main/java/com/google/devtools/build/lib/syntax/ValidationEnvironment.java
@@ -164,8 +164,8 @@ // no-op } else if (lhs instanceof IndexExpression) { visit(lhs); - } else if (lhs instanceof ListLiteral) { - for (Expression elem : ((ListLiteral) lhs).getElements()) { + } else if (lhs instanceof ListExpression) { + for (Expression elem : ((ListExpression) lhs).getElements()) { assign(elem); } } else { @@ -309,7 +309,7 @@ @Override public void visit(AugmentedAssignmentStatement node) { - if (node.getLHS() instanceof ListLiteral) { + if (node.getLHS() instanceof ListExpression) { throw new ValidationException( node.getLocation(), "cannot perform augmented assignment on a list or tuple expression"); }
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java index b691ee7..349aaae 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/ParserTest.java
@@ -76,23 +76,23 @@ } } - // helper func for testListLiterals: + // helper func for testListExpressions: private static int getIntElem(DictExpression.Entry entry, boolean key) { return ((IntegerLiteral) (key ? entry.getKey() : entry.getValue())).getValue(); } - // helper func for testListLiterals: - private static int getIntElem(ListLiteral list, int index) { + // helper func for testListExpressions: + private static int getIntElem(ListExpression list, int index) { return ((IntegerLiteral) list.getElements().get(index)).getValue(); } - // helper func for testListLiterals: + // helper func for testListExpressions: private static DictExpression.Entry getElem(DictExpression list, int index) { return list.getEntries().get(index); } - // helper func for testListLiterals: - private static Expression getElem(ListLiteral list, int index) { + // helper func for testListExpressions: + private static Expression getElem(ListExpression list, int index) { return list.getElements().get(index); } @@ -456,7 +456,7 @@ assertThat(statements).hasSize(1); assertThat(statements.get(0)).isInstanceOf(AssignmentStatement.class); AssignmentStatement assign = (AssignmentStatement) statements.get(0); - assertThat(assign.getLHS()).isInstanceOf(ListLiteral.class); + assertThat(assign.getLHS()).isInstanceOf(ListExpression.class); } @Test @@ -511,7 +511,7 @@ public void testListPositions() throws Exception { String expr = "[0,f(1),2]"; assertExpressionLocationCorrect(expr); - ListLiteral list = (ListLiteral) parseExpression(expr); + ListExpression list = (ListExpression) parseExpression(expr); assertThat(getText(expr, getElem(list, 0))).isEqualTo("0"); assertThat(getText(expr, getElem(list, 1))).isEqualTo("f(1)"); assertThat(getText(expr, getElem(list, 2))).isEqualTo("2"); @@ -641,8 +641,8 @@ } @Test - public void testListLiterals1() throws Exception { - ListLiteral list = (ListLiteral) parseExpression("[0,1,2]"); + public void testListExpressions1() throws Exception { + ListExpression list = (ListExpression) parseExpression("[0,1,2]"); assertThat(list.isTuple()).isFalse(); assertThat(list.getElements()).hasSize(3); assertThat(list.isTuple()).isFalse(); @@ -653,7 +653,7 @@ @Test public void testTupleLiterals2() throws Exception { - ListLiteral tuple = (ListLiteral) parseExpression("(0,1,2)"); + ListExpression tuple = (ListExpression) parseExpression("(0,1,2)"); assertThat(tuple.isTuple()).isTrue(); assertThat(tuple.getElements()).hasSize(3); assertThat(tuple.isTuple()).isTrue(); @@ -664,7 +664,7 @@ @Test public void testTupleWithoutParens() throws Exception { - ListLiteral tuple = (ListLiteral) parseExpression("0, 1, 2"); + ListExpression tuple = (ListExpression) parseExpression("0, 1, 2"); assertThat(tuple.isTuple()).isTrue(); assertThat(tuple.getElements()).hasSize(3); assertThat(tuple.isTuple()).isTrue(); @@ -686,7 +686,7 @@ assertContainsError("Trailing comma"); clearEvents(); - ListLiteral tuple = (ListLiteral) parseExpression("(0, 1, 2, 3,)"); + ListExpression tuple = (ListExpression) parseExpression("(0, 1, 2, 3,)"); assertThat(tuple.isTuple()).isTrue(); assertThat(tuple.getElements()).hasSize(4); assertThat(tuple.isTuple()).isTrue(); @@ -697,14 +697,14 @@ @Test public void testTupleLiterals3() throws Exception { - ListLiteral emptyTuple = (ListLiteral) parseExpression("()"); + ListExpression emptyTuple = (ListExpression) parseExpression("()"); assertThat(emptyTuple.isTuple()).isTrue(); assertThat(emptyTuple.getElements()).isEmpty(); } @Test public void testTupleLiterals4() throws Exception { - ListLiteral singletonTuple = (ListLiteral) parseExpression("(42,)"); + ListExpression singletonTuple = (ListExpression) parseExpression("(42,)"); assertThat(singletonTuple.isTuple()).isTrue(); assertThat(singletonTuple.getElements()).hasSize(1); assertThat(getIntElem(singletonTuple, 0)).isEqualTo(42); @@ -717,23 +717,23 @@ } @Test - public void testListLiterals6() throws Exception { - ListLiteral emptyList = (ListLiteral) parseExpression("[]"); + public void testListExpressions6() throws Exception { + ListExpression emptyList = (ListExpression) parseExpression("[]"); assertThat(emptyList.isTuple()).isFalse(); assertThat(emptyList.getElements()).isEmpty(); } @Test - public void testListLiterals7() throws Exception { - ListLiteral singletonList = (ListLiteral) parseExpression("[42,]"); + public void testListExpressions7() throws Exception { + ListExpression singletonList = (ListExpression) parseExpression("[42,]"); assertThat(singletonList.isTuple()).isFalse(); assertThat(singletonList.getElements()).hasSize(1); assertThat(getIntElem(singletonList, 0)).isEqualTo(42); } @Test - public void testListLiterals8() throws Exception { - ListLiteral singletonList = (ListLiteral) parseExpression("[42]"); // a singleton + public void testListExpressions8() throws Exception { + ListExpression singletonList = (ListExpression) parseExpression("[42]"); // a singleton assertThat(singletonList.isTuple()).isFalse(); assertThat(singletonList.getElements()).hasSize(1); assertThat(getIntElem(singletonList, 0)).isEqualTo(42); @@ -777,9 +777,9 @@ } @Test - public void testListLiterals9() throws Exception { - ListLiteral singletonList = - (ListLiteral) parseExpression("[ abi + opt_level + \'/include\' ]"); + public void testListExpressions9() throws Exception { + ListExpression singletonList = + (ListExpression) parseExpression("[ abi + opt_level + \'/include\' ]"); assertThat(singletonList.isTuple()).isFalse(); assertThat(singletonList.getElements()).hasSize(1); } @@ -831,7 +831,7 @@ assertThat(clauses).hasSize(1); Comprehension.For for0 = (Comprehension.For) clauses.get(0); assertThat(for0.getVars().toString()).isEqualTo("x"); - assertThat(for0.getIterable()).isInstanceOf(ListLiteral.class); + assertThat(for0.getIterable()).isInstanceOf(ListExpression.class); } @Test @@ -843,7 +843,7 @@ assertThat(clauses).hasSize(2); Comprehension.For for0 = (Comprehension.For) clauses.get(0); assertThat(for0.getVars().toString()).isEqualTo("x"); - assertThat(for0.getIterable()).isInstanceOf(ListLiteral.class); + assertThat(for0.getIterable()).isInstanceOf(ListExpression.class); Comprehension.For for1 = (Comprehension.For) clauses.get(1); assertThat(for1.getVars().toString()).isEqualTo("y"); assertThat(for1.getIterable()).isInstanceOf(Identifier.class);
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java index 69de404..0df5a53 100644 --- a/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java +++ b/src/test/java/com/google/devtools/build/lib/syntax/SkylarkEvaluationTest.java
@@ -1587,7 +1587,7 @@ } @Test - public void testInvalidAugmentedAssignment_ListLiteral() throws Exception { + public void testInvalidAugmentedAssignment_ListExpression() throws Exception { new SkylarkTest().testIfErrorContains( "cannot perform augmented assignment on a list or tuple expression", "def f(a, b):",