More flexible LValue syntax

--
MOS_MIGRATED_REVID=131056178
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index f8823b9..3e677be 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -908,11 +908,12 @@
   }
 
   @Test
-  public void testStructDictMembersAreImmutable() throws Exception {
-    checkErrorContains(
-        "can only assign to variables and tuples, not to 's.x['b']'",
+  public void testStructDictMembersAreMutable() throws Exception {
+    eval(
         "s = struct(x = {'a' : 1})",
         "s.x['b'] = 2\n");
+    assertThat(((SkylarkClassObject) lookup("s")).getValue("x"))
+        .isEqualTo(ImmutableMap.of("a", 1, "b", 2));
   }
 
   @Test
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 8f0a6f0..a0a09e8 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
@@ -868,6 +868,36 @@
   }
 
   @Test
+  public void testNestedDictAssignmentAsLValue() throws Exception {
+    new SkylarkTest().setUp("def func():",
+        "  d = {'a' : 1}",
+        "  e = {'d': d}",
+        "  e['d']['b'] = 2",
+        "  return e",
+        "e = func()").testLookup("e", ImmutableMap.of("d", ImmutableMap.of("a", 1, "b", 2)));
+  }
+
+  @Test
+  public void testListAssignmentAsLValue() throws Exception {
+    new SkylarkTest().setUp("def func():",
+        "  a = [1, 2]",
+        "  a[1] = 3",
+        "  a[-2] = 4",
+        "  return a",
+        "a = str(func())").testLookup("a", "[4, 3]");
+  }
+
+  @Test
+  public void testNestedListAssignmentAsLValue() throws Exception {
+    new SkylarkTest().setUp("def func():",
+        "  d = [1, 2]",
+        "  e = [3, d]",
+        "  e[1][1] = 4",
+        "  return e",
+        "e = str(func())").testLookup("e", "[3, [1, 4]]");
+  }
+  
+  @Test
   public void testDictTupleAssignmentAsLValue() throws Exception {
     new SkylarkTest().setUp("def func():",
         "  d = {'a' : 1}",
@@ -902,20 +932,6 @@
   }
 
   @Test
-  public void testListIndexAsLValueAsLValue() throws Exception {
-    new SkylarkTest()
-        .testIfErrorContains(
-            "can only assign an element in a dictionary, not in a 'list'",
-            "def id(l):",
-            "  return l",
-            "def func():",
-            "  l = id([1])",
-            "  l[0] = 2",
-            "  return l",
-            "l = func()");
-  }
-
-  @Test
   public void testTopLevelDict() throws Exception {
     new SkylarkTest().setUp("if 1:",
       "  v = 'a'",
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
index b7bd6f6..661b863 100644
--- a/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/syntax/ValidationTest.java
@@ -139,13 +139,11 @@
 
   @Test
   public void testFuncReturningDictAssignmentAsLValue() throws Exception {
-    checkError(
-        "can only assign to variables and tuples, not to 'my_dict()['b']'",
+    parse(
         "def my_dict():",
         "  return {'a': 1}",
         "def func():",
-        "  my_dict()['b'] = 2",
-        "  return d\n");
+        "  my_dict()['b'] = 2");
   }
 
   @Test