Simplify Skylark tests

Use the new EvaluationContext infrastructure to simplify Skylark tests
(said infrastructure is originally based on code from these tests).

Merge AbstractEvaluationTestCase and AbstractParserTestCase into
a non-abstract class EvaluationTestCase that uses EvaluationContext.
Cleanup the EventCollectionApparatus it uses.
Refactor all Skylark tests to use this new infrastructure.
Fix EvaluationTest and MethodLibraryTest to actually and correctly
run tests in both modes.

Fix small bugs in the main code base discovered by actually running the
code in both modes, and make error messages identical when possible.

--
MOS_MIGRATED_REVID=90828053
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
index 7b8c2df..5624ba7 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/BinaryOperatorExpression.java
@@ -391,6 +391,7 @@
       case IN: {
         if (rtype.isList()
             || rtype.isSet()
+            || rtype.isNset()
             || rtype.isDict()
             || rtype == SkylarkType.STRING) {
           return SkylarkType.BOOL;
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
index db47743..9f4cd83 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/EvalUtils.java
@@ -632,7 +632,7 @@
       return toCollection(o, loc);
     } else {
       throw new EvalException(loc,
-          "type '" + getDataTypeName(o) + "' is not an iterable");
+          "type '" + getDataTypeName(o) + "' is not iterable");
     }
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/LValue.java b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
index d2e3925..e7f15d7 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/LValue.java
@@ -126,7 +126,7 @@
       return;
     }
     throw new EvalException(loc,
-        "can only assign to variables, not to '" + expr + "'");
+        "can only assign to variables and tuples, not to '" + expr + "'");
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
index bfb7336..b264dd6 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkEnvironment.java
@@ -187,16 +187,6 @@
   }
 
   /**
-   * Updates the value of variable "varname" in the environment, corresponding
-   * to an AssignmentStatement.
-   */
-  @Override
-  public void update(String varname, Object value) {
-    Preconditions.checkNotNull(value, "update(value == null)");
-    env.put(varname, value);
-  }
-
-  /**
    * Returns the class of the variable or null if the variable does not exist. This function
    * works only in the local Environment, it doesn't check the global Environment.
    */
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
index ab740a4..92ae48b 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/SkylarkType.java
@@ -107,7 +107,7 @@
 
   /** @return true if any object of this SkylarkType can be cast to that Java class */
   public boolean canBeCastTo(Class<?> type) {
-    return Simple.of(type).includes(this);
+    return SkylarkType.of(type).includes(this);
   }
 
   /** @return true if some non-null objects of that Java class can be cast to this SkylarkType
@@ -498,6 +498,8 @@
       return LIST;
     } else if (SkylarkNestedSet.class.isAssignableFrom(type)) {
       return SET;
+    } else if (Function.class.isAssignableFrom(type)) {
+      return new SkylarkFunctionType("unknown", TOP);
     } else {
       return Simple.of(type);
     }
@@ -776,11 +778,7 @@
   /** Build a map of the given key, value types from an Iterable of Map.Entry-s */
   public static <KEY_TYPE, VALUE_TYPE> ImmutableMap<KEY_TYPE, VALUE_TYPE> toMap(
       Iterable<Map.Entry<KEY_TYPE, VALUE_TYPE>> obj) {
-    ImmutableMap.Builder<KEY_TYPE, VALUE_TYPE> builder = ImmutableMap.builder();
-    for (Map.Entry<KEY_TYPE, VALUE_TYPE> entry : obj) {
-      builder.put(entry.getKey(), entry.getValue());
-    }
-    return builder.build();
+    return ImmutableMap.copyOf(obj);
   }
 
   /**
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 a3c1991..95d7f30 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
@@ -106,7 +106,7 @@
   /**
    * Updates the variable type if the new type is "stronger" then the old one.
    * The old and the new vartype has to be compatible, otherwise an EvalException is thrown.
-   * The new type is stronger if the old one doesn't exist or unknown.
+   * The new type is stronger if the old one doesn't exist or is unknown.
    */
   public void update(String varname, SkylarkType newVartype, Location location)
       throws EvalException {
@@ -192,8 +192,9 @@
       SkylarkType functionType = functions.get(funcName);
       if (functionType != null && functionType != SkylarkType.UNKNOWN) {
         if (!(functionType instanceof SkylarkFunctionType)) {
-          throw new EvalException(loc, (objectType == SkylarkType.GLOBAL ? "" : objectType + ".")
-              + funcName + " is not a function");
+          throw new EvalException(loc, String.format("%s%s is not a function but a(n) %s",
+                  (objectType == SkylarkType.GLOBAL ? "" : objectType + "."),
+                  funcName, functionType));
         }
         return ((SkylarkFunctionType) functionType).getReturnType();
       }