Create infrastructure for convenient control of Starlark Params by semantic flag

Also migrate ~3 examples of parameter control to use the new infrastructure, as a manner of demonstration.

RELNOTES: None.
PiperOrigin-RevId: 221332133
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
index fb2831b..b332f98 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkIntegrationTest.java
@@ -1081,7 +1081,9 @@
 
     reporter.removeHandler(failFastHandler);
     getConfiguredTarget("//test:r");
-    assertContainsEvent("'default' is no longer a supported parameter for attr.output");
+    assertContainsEvent(
+        "parameter 'default' is deprecated and will be removed soon. It may be "
+            + "temporarily re-enabled by setting --incompatible_no_output_attr_default=false");
   }
 
   @Test
@@ -1129,7 +1131,9 @@
 
     reporter.removeHandler(failFastHandler);
     getConfiguredTarget("//test:r");
-    assertContainsEvent("'default' is no longer a supported parameter for attr.output_list");
+    assertContainsEvent(
+        "parameter 'default' is deprecated and will be removed soon. It may be "
+            + "temporarily re-enabled by setting --incompatible_no_output_attr_default=false");
   }
 
   @Test
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 60dc76f..7579775 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
@@ -771,15 +771,14 @@
   public void testRuleUnknownKeyword() throws Exception {
     registerDummyUserDefinedFunction();
     checkErrorContains(
-        "unexpected keyword 'bad_keyword' in call to " + "rule(implementation: function, ",
+        "unexpected keyword 'bad_keyword', in call to rule(function, string bad_keyword)",
         "rule(impl, bad_keyword = 'some text')");
   }
 
   @Test
   public void testRuleImplementationMissing() throws Exception {
     checkErrorContains(
-        "missing mandatory positional argument 'implementation' while calling "
-            + "rule(implementation",
+        "parameter 'implementation' has no default value, in call to rule(dict attrs)",
         "rule(attrs = {})");
   }
 
@@ -787,8 +786,8 @@
   public void testRuleBadTypeForAdd() throws Exception {
     registerDummyUserDefinedFunction();
     checkErrorContains(
-        "expected dict or NoneType for 'attrs' while calling rule but got string instead: "
-            + "some text",
+        "expected value of type 'dict or NoneType' for parameter 'attrs', "
+            + "in call to rule(function, string attrs)",
         "rule(impl, attrs = 'some text')");
   }
 
@@ -804,7 +803,7 @@
   public void testRuleBadTypeForDoc() throws Exception {
     registerDummyUserDefinedFunction();
     checkErrorContains(
-        "expected string for 'doc' while calling rule but got int instead",
+        "expected value of type 'string' for parameter 'doc', in call to rule(function, int doc)",
         "rule(impl, doc = 1)");
   }
 
@@ -1416,7 +1415,7 @@
   @Test
   public void declaredProvidersBadTypeForDoc() throws Exception {
     checkErrorContains(
-        "expected string for 'doc' while calling provider but got int instead",
+        "expected value of type 'string' for parameter 'doc', in call to provider(int doc)",
         "provider(doc = 1)");
   }
 
@@ -1559,7 +1558,7 @@
   public void aspectBadTypeForDoc() throws Exception {
     registerDummyUserDefinedFunction();
     checkErrorContains(
-        "expected string for 'doc' while calling aspect but got int instead",
+        "expected value of type 'string' for parameter 'doc', in call to aspect(function, int doc)",
         "aspect(impl, doc = 1)");
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java
index 98bd519..aa78222 100644
--- a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/SkylarkCallableProcessorTest.java
@@ -317,6 +317,17 @@
   }
 
   @Test
+  public void testEnablingAndDisablingFlag_param() throws Exception {
+    assertAbout(javaSource())
+        .that(getFile("EnablingAndDisablingFlagParam.java"))
+        .processedWith(new SkylarkCallableProcessor())
+        .failsToCompile()
+        .withErrorContaining(
+            "Parameter 'two' has enableOnlyWithFlag and disableWithFlag set. "
+                + "At most one may be set");
+  }
+
+  @Test
   public void testConflictingMethodNames() throws Exception {
     assertAbout(javaSource())
         .that(getFile("ConflictingMethodNames.java"))
@@ -325,4 +336,33 @@
         .withErrorContaining("Containing class has more than one method with name "
             + "'conflicting_method' defined");
   }
+
+  @Test
+  public void testDisabledValueParamNoToggle() throws Exception {
+    assertAbout(javaSource())
+        .that(getFile("DisabledValueParamNoToggle.java"))
+        .processedWith(new SkylarkCallableProcessor())
+        .failsToCompile()
+        .withErrorContaining("Parameter 'two' has valueWhenDisabled set, but is always enabled");
+  }
+
+  @Test
+  public void testToggledKwargsParam() throws Exception {
+    assertAbout(javaSource())
+        .that(getFile("ToggledKwargsParam.java"))
+        .processedWith(new SkylarkCallableProcessor())
+        .failsToCompile()
+        .withErrorContaining("The extraKeywords parameter may not be toggled by semantic flag");
+  }
+
+  @Test
+  public void testToggledParamNoDisabledValue() throws Exception {
+    assertAbout(javaSource())
+        .that(getFile("ToggledParamNoDisabledValue.java"))
+        .processedWith(new SkylarkCallableProcessor())
+        .failsToCompile()
+        .withErrorContaining(
+            "Parameter 'two' may be disabled by semantic flag, "
+                + "thus valueWhenDisabled must be set");
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/DisabledValueParamNoToggle.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/DisabledValueParamNoToggle.java
new file mode 100644
index 0000000..16e4edb
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/DisabledValueParamNoToggle.java
@@ -0,0 +1,36 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface.processor.testsources;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+
+/**
+ * Test case for a SkylarkCallable method which has a parameter which has a "disabled value" set but
+ * is always-on.
+ */
+public class DisabledValueParamNoToggle {
+
+  @SkylarkCallable(
+      name = "no_toggle_method",
+      documented = false,
+      parameters = {
+        @Param(name = "one", named = true, positional = true),
+        @Param(name = "two", named = true, valueWhenDisabled = "3", positional = true)
+      })
+  public Integer noToggleMethod(Integer one, Integer two) {
+    return 42;
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/EnablingAndDisablingFlagParam.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/EnablingAndDisablingFlagParam.java
new file mode 100644
index 0000000..83274df
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/EnablingAndDisablingFlagParam.java
@@ -0,0 +1,42 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface.processor.testsources;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics.FlagIdentifier;
+
+/**
+ * Test case for a SkylarkCallable method which has a parameter with both enableOnlyWithFlag and
+ * disableWithFlag specified.
+ */
+public class EnablingAndDisablingFlagParam {
+
+  @SkylarkCallable(
+      name = "someMethod",
+      documented = false,
+      parameters = {
+        @Param(name = "one", type = String.class, named = true),
+        @Param(
+            name = "two",
+            type = Integer.class,
+            named = true,
+            enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API,
+            disableWithFlag = FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API),
+      })
+  public String someMethod(String one, Integer two) {
+    return "foo";
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledKwargsParam.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledKwargsParam.java
new file mode 100644
index 0000000..243b15a
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledKwargsParam.java
@@ -0,0 +1,51 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface.processor.testsources;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.syntax.Environment;
+import com.google.devtools.build.lib.syntax.SkylarkDict;
+import com.google.devtools.build.lib.syntax.SkylarkList;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics.FlagIdentifier;
+
+/**
+ * Test case for a SkylarkCallable method which has a "extraKeywords" parameter which has
+ * enableOnlyWithFlag set. (This is unsupported.)
+ */
+public class ToggledKwargsParam {
+
+  @SkylarkCallable(
+      name = "toggled_kwargs_method",
+      documented = false,
+      parameters = {
+        @Param(name = "one", type = String.class, named = true),
+        @Param(name = "two", type = Integer.class, named = true),
+      },
+      extraPositionals = @Param(name = "args"),
+      extraKeywords =
+          @Param(
+              name = "kwargs",
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API),
+      useEnvironment = true)
+  public String toggledKwargsMethod(
+      String one,
+      Integer two,
+      SkylarkList<?> args,
+      SkylarkDict<?, ?> kwargs,
+      Environment environment) {
+    return "cat";
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledParamNoDisabledValue.java b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledParamNoDisabledValue.java
new file mode 100644
index 0000000..eebbd28
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkinterface/processor/testsources/ToggledParamNoDisabledValue.java
@@ -0,0 +1,41 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.devtools.build.lib.skylarkinterface.processor.testsources;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics.FlagIdentifier;
+
+/**
+ * Test case for a SkylarkCallable method which has a parameter which may be disabled with semantic
+ * flag but has no "disabled value".
+ */
+public class ToggledParamNoDisabledValue {
+
+  @SkylarkCallable(
+      name = "no_disabled_value_method",
+      documented = false,
+      parameters = {
+        @Param(name = "one", named = true, positional = true),
+        @Param(
+            name = "two",
+            named = true,
+            enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_BUILD_SETTING_API,
+            positional = true)
+      })
+  public Integer noDisabledValueMethod(Integer one, Integer two) {
+    return 42;
+  }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFlagGuardingTest.java b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFlagGuardingTest.java
new file mode 100644
index 0000000..9839d9a
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/syntax/StarlarkFlagGuardingTest.java
@@ -0,0 +1,248 @@
+// Copyright 2018 The Bazel Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package com.google.devtools.build.lib.syntax;
+
+import com.google.devtools.build.lib.skylarkinterface.Param;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkCallable;
+import com.google.devtools.build.lib.skylarkinterface.SkylarkModule;
+import com.google.devtools.build.lib.syntax.SkylarkSemantics.FlagIdentifier;
+import com.google.devtools.build.lib.syntax.util.EvaluationTestCase;
+import com.google.devtools.build.lib.testutil.TestMode;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Starlark evaluation tests which verify the infrastructure which toggles build API methods and
+ * parameters with semantic flags.
+ */
+@RunWith(JUnit4.class)
+public class StarlarkFlagGuardingTest extends EvaluationTestCase {
+
+  @Before
+  public final void setup() throws Exception {
+    setMode(TestMode.SKYLARK);
+  }
+
+  /** Mock containing exposed methods for flag-guarding tests. */
+  @SkylarkModule(name = "Mock", doc = "")
+  public static class Mock {
+
+    @SkylarkCallable(
+        name = "positionals_only_method",
+        documented = false,
+        parameters = {
+          @Param(name = "a", positional = true, named = false, type = Integer.class),
+          @Param(
+              name = "b",
+              positional = true,
+              named = false,
+              type = Boolean.class,
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+              valueWhenDisabled = "False"),
+          @Param(name = "c", positional = true, named = false, type = Integer.class),
+        },
+        useEnvironment = true)
+    public String positionalsOnlyMethod(Integer a, boolean b, Integer c, Environment env) {
+      return "positionals_only_method(" + a + ", " + b + ", " + c + ")";
+    }
+
+    @SkylarkCallable(
+        name = "keywords_only_method",
+        documented = false,
+        parameters = {
+          @Param(name = "a", positional = false, named = true, type = Integer.class),
+          @Param(
+              name = "b",
+              positional = false,
+              named = true,
+              type = Boolean.class,
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+              valueWhenDisabled = "False"),
+          @Param(name = "c", positional = false, named = true, type = Integer.class),
+        },
+        useEnvironment = true)
+    public String keywordsOnlyMethod(Integer a, boolean b, Integer c, Environment env) {
+      return "keywords_only_method(" + a + ", " + b + ", " + c + ")";
+    }
+
+    @SkylarkCallable(
+        name = "mixed_params_method",
+        documented = false,
+        parameters = {
+          @Param(name = "a", positional = true, named = false, type = Integer.class),
+          @Param(
+              name = "b",
+              positional = true,
+              named = false,
+              type = Boolean.class,
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+              valueWhenDisabled = "False"),
+          @Param(
+              name = "c",
+              positional = false,
+              named = true,
+              type = Integer.class,
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+              valueWhenDisabled = "3"),
+          @Param(name = "d", positional = false, named = true, type = Boolean.class),
+        },
+        useEnvironment = true)
+    public String mixedParamsMethod(Integer a, boolean b, Integer c, boolean d, Environment env) {
+      return "mixed_params_method(" + a + ", " + b + ", " + c + ", " + d + ")";
+    }
+
+    @SkylarkCallable(
+        name = "keywords_multiple_flags",
+        documented = false,
+        parameters = {
+          @Param(name = "a", positional = false, named = true, type = Integer.class),
+          @Param(
+              name = "b",
+              positional = false,
+              named = true,
+              type = Boolean.class,
+              disableWithFlag = FlagIdentifier.INCOMPATIBLE_NO_ATTR_LICENSE,
+              valueWhenDisabled = "False"),
+          @Param(
+              name = "c",
+              positional = false,
+              named = true,
+              type = Integer.class,
+              enableOnlyWithFlag = FlagIdentifier.EXPERIMENTAL_ANALYSIS_TESTING_IMPROVEMENTS,
+              valueWhenDisabled = "3"),
+        },
+        useEnvironment = true)
+    public String keywordsMultipleFlags(Integer a, boolean b, Integer c, Environment env) {
+      return "keywords_multiple_flags(" + a + ", " + b + ", " + c + ")";
+    }
+  }
+
+  @Test
+  public void testPositionalsOnlyGuardedMethod() throws Exception {
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testEval(
+            "mock.positionals_only_method(1, True, 3)", "'positionals_only_method(1, true, 3)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "expected value of type 'bool' for parameter 'b', "
+                + "in method call positionals_only_method(int, int) of 'Mock'",
+            "mock.positionals_only_method(1, 3)");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testEval("mock.positionals_only_method(1, 3)", "'positionals_only_method(1, false, 3)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "expected value of type 'int' for parameter 'c', "
+                + "in method call positionals_only_method(int, bool, int) of 'Mock'",
+            "mock.positionals_only_method(1, True, 3)");
+  }
+
+  @Test
+  public void testKeywordOnlyGuardedMethod() throws Exception {
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testEval(
+            "mock.keywords_only_method(a=1, b=True, c=3)", "'keywords_only_method(1, true, 3)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "parameter 'b' has no default value, in method call "
+                + "keywords_only_method(int a, int c) of 'Mock'",
+            "mock.keywords_only_method(a=1, c=3)");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testEval("mock.keywords_only_method(a=1, c=3)", "'keywords_only_method(1, false, 3)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "parameter 'b' is experimental and thus unavailable with the current "
+                + "flags. It may be enabled by setting "
+                + "--experimental_analysis_testing_improvements",
+            "mock.keywords_only_method(a=1, b=True, c=3)");
+  }
+
+  @Test
+  public void testMixedParamsMethod() throws Exception {
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testEval(
+            "mock.mixed_params_method(1, True, c=3, d=True)",
+            "'mixed_params_method(1, true, 3, true)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=true")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "parameter 'b' has no default value, in method call "
+                + "mixed_params_method(int, int c) of 'Mock'",
+            "mock.mixed_params_method(1, c=3)");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testEval(
+            "mock.mixed_params_method(1, d=True)", "'mixed_params_method(1, false, 3, true)'");
+
+    new SkylarkTest("--experimental_analysis_testing_improvements=false")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "expected no more than 1 positional arguments, but got 2, "
+                + "in method call mixed_params_method(int, bool, int c, bool d) of 'Mock'",
+            "mock.mixed_params_method(1, True, c=3, d=True)");
+  }
+
+  @Test
+  public void testKeywordsMultipleFlags() throws Exception {
+    new SkylarkTest(
+            "--experimental_analysis_testing_improvements=true",
+            "--incompatible_no_attr_license=false")
+        .update("mock", new Mock())
+        .testEval(
+            "mock.keywords_multiple_flags(a=42, b=True, c=0)",
+            "'keywords_multiple_flags(42, true, 0)'");
+
+    new SkylarkTest(
+            "--experimental_analysis_testing_improvements=true",
+            "--incompatible_no_attr_license=false")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "parameter 'b' has no default value, in method call "
+                + "keywords_multiple_flags(int a) of 'Mock'",
+            "mock.keywords_multiple_flags(a=42)");
+
+    new SkylarkTest(
+            "--experimental_analysis_testing_improvements=false",
+            "--incompatible_no_attr_license=true")
+        .update("mock", new Mock())
+        .testEval("mock.keywords_multiple_flags(a=42)", "'keywords_multiple_flags(42, false, 3)'");
+
+    new SkylarkTest(
+            "--experimental_analysis_testing_improvements=false",
+            "--incompatible_no_attr_license=true")
+        .update("mock", new Mock())
+        .testIfErrorContains(
+            "parameter 'b' is deprecated and will be removed soon. It may be "
+                + "temporarily re-enabled by setting --incompatible_no_attr_license=false",
+            "mock.keywords_multiple_flags(a=42, b=True, c=0)");
+  }
+}
diff --git a/src/test/shell/integration/outputs_test.sh b/src/test/shell/integration/outputs_test.sh
index f31c4c9..ea0f772 100755
--- a/src/test/shell/integration/outputs_test.sh
+++ b/src/test/shell/integration/outputs_test.sh
@@ -170,7 +170,7 @@
   if bazel build //$pkg:demo &> $TEST_log; then
     fail "Build expected to fail"
   fi
-  expect_log "expected dict or dict-returning function or NoneType for 'outputs' while calling rule but got select of dict instead"
+  expect_log "expected value of type 'dict or NoneType or function' for parameter 'outputs', in call to rule"
 }
 
 function test_configurable_output_error() {