Migrate SkylarkBuiltin annotations to SkylarkSignature instead.

--
MOS_MIGRATED_REVID=91603959
diff --git a/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java
index 82a2f0a..9466c69 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/MethodLibrary.java
@@ -38,12 +38,13 @@
 import com.google.devtools.build.lib.syntax.MixedModeFunction;
 import com.google.devtools.build.lib.syntax.SelectorList;
 import com.google.devtools.build.lib.syntax.SelectorValue;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin;
-import com.google.devtools.build.lib.syntax.SkylarkBuiltin.Param;
 import com.google.devtools.build.lib.syntax.SkylarkEnvironment;
 import com.google.devtools.build.lib.syntax.SkylarkList;
 import com.google.devtools.build.lib.syntax.SkylarkModule;
 import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import com.google.devtools.build.lib.syntax.SkylarkSignature;
+import com.google.devtools.build.lib.syntax.SkylarkSignature.Param;
+import com.google.devtools.build.lib.syntax.SkylarkSignatureProcessor.HackHackEitherList;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -65,6 +66,16 @@
 
   private MethodLibrary() {}
 
+  // TODO(bazel-team):
+  // the Build language and Skylark currently have different list types:
+  // the Build language uses plain java List (usually ArrayList) which is mutable and accepts
+  // any argument, whereas Skylark uses SkylarkList which is immutable and accepts only
+  // arguments of the same kind. Some methods below use HackHackEitherList as a magic marker
+  // to indicate that either kind of lists is used depending on the evaluation context.
+  // It might be a good idea to either have separate methods for the two languages where it matters,
+  // or to unify the two languages so they use the same data structure (which might require
+  // updating all existing clients).
+
   // Convert string index in the same way Python does.
   // If index is negative, starts from the end.
   // If index is outside bounds, it is restricted to the valid range.
@@ -109,14 +120,15 @@
     return index;
   }
 
-    // supported string methods
+  // supported string methods
 
-  @SkylarkBuiltin(name = "join", objectType = StringModule.class, returnType = String.class,
+  @SkylarkSignature(name = "join", objectType = StringModule.class, returnType = String.class,
       doc = "Returns a string in which the string elements of the argument have been "
           + "joined by this string as a separator. Example:<br>"
           + "<pre class=\"language-python\">\"|\".join([\"a\", \"b\", \"c\"]) == \"a|b|c\"</pre>",
-      mandatoryParams = {
-      @Param(name = "elements", type = SkylarkList.class, doc = "The objects to join.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string, a separator."),
+        @Param(name = "elements", type = HackHackEitherList.class, doc = "The objects to join.")})
   private static Function join = new MixedModeFunction("join",
       ImmutableList.of("this", "elements"), 2, false) {
     @Override
@@ -126,9 +138,11 @@
       return Joiner.on(thisString).join(seq);
     }};
 
-  @SkylarkBuiltin(name = "lower", objectType = StringModule.class, returnType = String.class,
-      doc = "Returns the lower case version of this string.")
-      private static Function lower = new MixedModeFunction("lower",
+  @SkylarkSignature(name = "lower", objectType = StringModule.class, returnType = String.class,
+      doc = "Returns the lower case version of this string.",
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string, to convert to lower case.")})
+  private static Function lower = new MixedModeFunction("lower",
           ImmutableList.of("this"), 1, false) {
     @Override
     public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
@@ -137,8 +151,10 @@
     }
   };
 
-  @SkylarkBuiltin(name = "upper", objectType = StringModule.class, returnType = String.class,
-      doc = "Returns the upper case version of this string.")
+  @SkylarkSignature(name = "upper", objectType = StringModule.class, returnType = String.class,
+      doc = "Returns the upper case version of this string.",
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string, to convert to upper case.")})
     private static Function upper = new MixedModeFunction("upper",
         ImmutableList.of("this"), 1, false) {
     @Override
@@ -148,15 +164,18 @@
     }
   };
 
-  @SkylarkBuiltin(name = "replace", objectType = StringModule.class, returnType = String.class,
+  @SkylarkSignature(name = "replace", objectType = StringModule.class, returnType = String.class,
       doc = "Returns a copy of the string in which the occurrences "
           + "of <code>old</code> have been replaced with <code>new</code>, optionally restricting "
           + "the number of replacements to <code>maxsplit</code>.",
-      mandatoryParams = {
-      @Param(name = "old", type = String.class, doc = "The string to be replaced."),
-      @Param(name = "new", type = String.class, doc = "The string to replace with.")},
-      optionalParams = {
-      @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of replacements.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "old", type = String.class, doc = "The string to be replaced."),
+        @Param(name = "new", type = String.class, doc = "The string to replace with.")},
+      optionalPositionals = {
+        @Param(name = "maxsplit", type = Integer.class,
+            doc = "The maximum number of replacements.")},
+      useLocation = true)
   private static Function replace =
     new MixedModeFunction("replace", ImmutableList.of("this", "old", "new", "maxsplit"), 3, false) {
     @Override
@@ -182,13 +201,17 @@
     }
   };
 
-  @SkylarkBuiltin(name = "split", objectType = StringModule.class, returnType = SkylarkList.class,
+  @SkylarkSignature(name = "split", objectType = StringModule.class,
+      returnType = HackHackEitherList.class,
       doc = "Returns a list of all the words in the string, using <code>sep</code>  "
           + "as the separator, optionally limiting the number of splits to <code>maxsplit</code>.",
-      optionalParams = {
-      @Param(name = "sep", type = String.class,
-          doc = "The string to split on, default is space (\" \")."),
-      @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of splits.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string.")},
+      optionalPositionals = {
+        @Param(name = "sep", type = String.class,
+            doc = "The string to split on, default is space (\" \")."),
+        @Param(name = "maxsplit", type = Integer.class, doc = "The maximum number of splits.")},
+      useEnvironment = true)
   private static Function split = new MixedModeFunction("split",
       ImmutableList.of("this", "sep", "maxsplit"), 1, false) {
     @Override
@@ -233,16 +256,19 @@
     return stringFind(forward, thiz, sub, start, args[3], functionName + " argument");
   }
 
-  @SkylarkBuiltin(name = "rfind", objectType = StringModule.class, returnType = Integer.class,
+  @SkylarkSignature(name = "rfind", objectType = StringModule.class, returnType = Integer.class,
       doc = "Returns the last index where <code>sub</code> is found, "
           + "or -1 if no such index exists, optionally restricting to "
           + "[<code>start</code>:<code>end</code>], "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to find.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
-      @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Restrict to search from this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "optional position before which to restrict to search.")})
   private static Function rfind =
       new MixedModeFunction("rfind", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -251,16 +277,19 @@
         }
       };
 
-  @SkylarkBuiltin(name = "find", objectType = StringModule.class, returnType = Integer.class,
+  @SkylarkSignature(name = "find", objectType = StringModule.class, returnType = Integer.class,
       doc = "Returns the first index where <code>sub</code> is found, "
           + "or -1 if no such index exists, optionally restricting to "
           + "[<code>start</code>:<code>end]</code>, "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to find.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
-      @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Restrict to search from this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "optional position before which to restrict to search.")})
   private static Function find =
       new MixedModeFunction("find", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -270,16 +299,20 @@
         }
       };
 
-  @SkylarkBuiltin(name = "rindex", objectType = StringModule.class, returnType = Integer.class,
+  @SkylarkSignature(name = "rindex", objectType = StringModule.class, returnType = Integer.class,
       doc = "Returns the last index where <code>sub</code> is found, "
           + "or throw an error if no such index exists, optionally restricting to "
           + "[<code>start</code>:<code>end</code>], "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to find.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
-      @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Restrict to search from this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "optional position before which to restrict to search.")},
+      useLocation = true)
   private static Function rindex =
       new MixedModeFunction("rindex", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -295,16 +328,20 @@
         }
       };
 
-  @SkylarkBuiltin(name = "index", objectType = StringModule.class, returnType = Integer.class,
+  @SkylarkSignature(name = "index", objectType = StringModule.class, returnType = Integer.class,
       doc = "Returns the first index where <code>sub</code> is found, "
           + "or throw an error if no such index exists, optionally restricting to "
           + "[<code>start</code>:<code>end]</code>, "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to find.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
-      @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to find.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Restrict to search from this position."),
+        @Param(name = "end", type = Integer.class, noneable = true,
+            doc = "optional position before which to restrict to search.")},
+      useLocation = true)
   private static Function index =
       new MixedModeFunction("index", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -320,15 +357,18 @@
         }
       };
 
-  @SkylarkBuiltin(name = "count", objectType = StringModule.class, returnType = Integer.class,
+  @SkylarkSignature(name = "count", objectType = StringModule.class, returnType = Integer.class,
       doc = "Returns the number of (non-overlapping) occurrences of substring <code>sub</code> in "
           + "string, optionally restricting to [<code>start</code>:<code>end</code>], "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to count.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Restrict to search from this position."),
-      @Param(name = "end", type = Integer.class, doc = "Restrict to search before this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to count.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Restrict to search from this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "optional position before which to restrict to search.")})
   private static Function count =
       new MixedModeFunction("count", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -354,15 +394,18 @@
         }
       };
 
-  @SkylarkBuiltin(name = "endswith", objectType = StringModule.class, returnType = Boolean.class,
+  @SkylarkSignature(name = "endswith", objectType = StringModule.class, returnType = Boolean.class,
       doc = "Returns True if the string ends with <code>sub</code>, "
           + "otherwise False, optionally restricting to [<code>start</code>:<code>end</code>], "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to check.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Test beginning at this position."),
-      @Param(name = "end", type = Integer.class, doc = "Stop comparing at this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to check.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Test beginning at this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "optional position at which to stop comparing.")})
   private static Function endswith =
       new MixedModeFunction("endswith", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
         @Override
@@ -379,15 +422,19 @@
         }
       };
 
-  @SkylarkBuiltin(name = "startswith", objectType = StringModule.class, returnType = Boolean.class,
+  @SkylarkSignature(name = "startswith", objectType = StringModule.class,
+      returnType = Boolean.class,
       doc = "Returns True if the string starts with <code>sub</code>, "
           + "otherwise False, optionally restricting to [<code>start</code>:<code>end</code>], "
           + "<code>start</code> being inclusive and <code>end</code> being exclusive.",
-      mandatoryParams = {
-      @Param(name = "sub", type = String.class, doc = "The substring to check.")},
-      optionalParams = {
-      @Param(name = "start", type = Integer.class, doc = "Test beginning at this position."),
-      @Param(name = "end", type = Integer.class, doc = "Stop comparing at this position.")})
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string."),
+        @Param(name = "sub", type = String.class, doc = "The substring to check.")},
+      optionalPositionals = {
+        @Param(name = "start", type = Integer.class, defaultValue = "0",
+            doc = "Test beginning at this position."),
+        @Param(name = "end", type = Integer.class, noneable = true, defaultValue = "None",
+            doc = "Stop comparing at this position.")})
   private static Function startswith =
     new MixedModeFunction("startswith", ImmutableList.of("this", "sub", "start", "end"), 2, false) {
     @Override
@@ -404,9 +451,11 @@
   };
 
   // TODO(bazel-team): Maybe support an argument to tell the type of the whitespace.
-  @SkylarkBuiltin(name = "strip", objectType = StringModule.class, returnType = String.class,
+  @SkylarkSignature(name = "strip", objectType = StringModule.class, returnType = String.class,
       doc = "Returns a copy of the string in which all whitespace characters "
-          + "have been stripped from the beginning and the end of the string.")
+          + "have been stripped from the beginning and the end of the string.",
+      mandatoryPositionals = {
+        @Param(name = "self", type = String.class, doc = "This string.")})
   private static Function strip =
       new MixedModeFunction("strip", ImmutableList.of("this"), 1, false) {
         @Override
@@ -418,8 +467,13 @@
       };
 
   // slice operator
-  @SkylarkBuiltin(name = "$slice", documented = false,
-      doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.")
+  @SkylarkSignature(name = "$slice", documented = false,
+      mandatoryPositionals = {
+        @Param(name = "self", type = Object.class, doc = "This string, list or tuple."),
+        @Param(name = "start", type = Integer.class, doc = "start position of the slice."),
+        @Param(name = "end", type = Integer.class, doc = "end position of the slice.")},
+      doc = "x[<code>start</code>:<code>end</code>] returns a slice or a list slice.",
+      useLocation = true, useEnvironment = true)
   private static Function slice = new MixedModeFunction("$slice",
       ImmutableList.of("this", "start", "end"), 3, false) {
     @Override
@@ -448,24 +502,34 @@
   };
 
   // supported list methods
-  @SkylarkBuiltin(name = "sorted", doc = "Sort a collection.")
+  @SkylarkSignature(name = "sorted", returnType = HackHackEitherList.class,
+      doc = "Sort a collection.",
+      mandatoryPositionals = {
+        @Param(name = "self", type = HackHackEitherList.class, doc = "This list.")},
+        useLocation = true, useEnvironment = true)
   private static Function sorted = new MixedModeFunction("sorted",
-      ImmutableList.of("this"), 1, false) {
+      ImmutableList.of("self"), 1, false) {
     @Override
     public Object call(Object[] args, FuncallExpression ast, Environment env)
         throws EvalException, ConversionException {
-      List<Object> thiz = Type.OBJECT_LIST.convert(args[0], "'sorted' operand");
+      List<Object> self = Type.OBJECT_LIST.convert(args[0], "'sorted' operand");
       try {
-        thiz = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(thiz);
+        self = Ordering.from(EvalUtils.SKYLARK_COMPARATOR).sortedCopy(self);
       } catch (EvalUtils.ComparisonException e) {
         throw new EvalException(ast.getLocation(), e);
       }
-      return convert(thiz, env, ast.getLocation());
+      return convert(self, env, ast.getLocation());
     }
   };
 
-  @SkylarkBuiltin(name = "append", documented = false,
-      doc = "Adds an item to the end of the list.")
+  // This function has a SkylarkSignature but is only used by the Build language, not Skylark.
+  @SkylarkSignature(name = "append", returnType = Environment.NoneType.class, documented = false,
+      doc = "Adds an item to the end of the list.",
+      mandatoryPositionals = {
+        // we use List rather than SkylarkList because this is actually for use *outside* Skylark
+        @Param(name = "self", type = List.class, doc = "This list."),
+        @Param(name = "item", type = Object.class, doc = "Item to add at the end.")},
+        useLocation = true, useEnvironment = true)
   private static Function append = new MixedModeFunction("append",
       ImmutableList.of("this", "x"), 2, false) {
     @Override
@@ -477,8 +541,14 @@
     }
   };
 
-  @SkylarkBuiltin(name = "extend", documented = false,
-      doc = "Adds all items to the end of the list.")
+  // This function has a SkylarkSignature but is only used by the Build language, not Skylark.
+  @SkylarkSignature(name = "extend", returnType = Environment.NoneType.class, documented = false,
+      doc = "Adds all items to the end of the list.",
+      mandatoryPositionals = {
+        // we use List rather than SkylarkList because this is actually for use *outside* Skylark
+        @Param(name = "self", type = List.class, doc = "This list."),
+        @Param(name = "items", type = List.class, doc = "Items to add at the end.")},
+        useLocation = true, useEnvironment = true)
   private static Function extend = new MixedModeFunction("extend",
           ImmutableList.of("this", "x"), 2, false) {
     @Override
@@ -492,9 +562,13 @@
   };
 
   // dictionary access operator
-  @SkylarkBuiltin(name = "$index", documented = false,
+  @SkylarkSignature(name = "$index", documented = false,
       doc = "Returns the nth element of a list or string, "
-          + "or looks up a value in a dictionary.")
+          + "or looks up a value in a dictionary.",
+      mandatoryPositionals = {
+        @Param(name = "self", type = Object.class, doc = "This object."),
+        @Param(name = "key", type = Object.class, doc = "The index or key to access.")},
+      useLocation = true)
   private static Function indexOperator = new MixedModeFunction("$index",
       ImmutableList.of("this", "index"), 2, false) {
     @Override
@@ -543,10 +617,13 @@
     }
   };
 
-  @SkylarkBuiltin(name = "values", objectType = DictModule.class, returnType = SkylarkList.class,
+  @SkylarkSignature(name = "values", objectType = DictModule.class,
+      returnType = HackHackEitherList.class,
       doc = "Return the list of values. Dictionaries are always sorted by their keys:"
           + "<pre class=\"language-python\">"
-          + "{2: \"a\", 4: \"b\", 1: \"c\"}.values() == [\"c\", \"a\", \"b\"]</pre>\n")
+          + "{2: \"a\", 4: \"b\", 1: \"c\"}.values() == [\"c\", \"a\", \"b\"]</pre>\n",
+      mandatoryPositionals = {@Param(name = "self", type = Map.class, doc = "This dict.")},
+      useLocation = true, useEnvironment = true)
   private static Function values = new NoArgFunction("values") {
     @Override
     public Object call(Object self, FuncallExpression ast, Environment env)
@@ -557,11 +634,15 @@
     }
   };
 
-  @SkylarkBuiltin(name = "items", objectType = DictModule.class, returnType = SkylarkList.class,
+  @SkylarkSignature(name = "items", objectType = DictModule.class,
+      returnType = HackHackEitherList.class,
       doc = "Return the list of key-value tuples. Dictionaries are always sorted by their keys:"
           + "<pre class=\"language-python\">"
           + "{2: \"a\", 4: \"b\", 1: \"c\"}.items() == [(1, \"c\"), (2, \"a\"), (4, \"b\")]"
-          + "</pre>\n")
+          + "</pre>\n",
+      mandatoryPositionals = {
+        @Param(name = "self", type = Map.class, doc = "This dict.")},
+      useLocation = true, useEnvironment = true)
   private static Function items = new NoArgFunction("items") {
     @Override
     public Object call(Object self, FuncallExpression ast, Environment env)
@@ -577,10 +658,14 @@
     }
   };
 
-  @SkylarkBuiltin(name = "keys", objectType = DictModule.class, returnType = SkylarkList.class,
+  @SkylarkSignature(name = "keys", objectType = DictModule.class,
+      returnType = HackHackEitherList.class,
       doc = "Return the list of keys. Dictionaries are always sorted by their keys:"
           + "<pre class=\"language-python\">{2: \"a\", 4: \"b\", 1: \"c\"}.keys() == [1, 2, 4]"
-          + "</pre>\n")
+          + "</pre>\n",
+      mandatoryPositionals = {
+        @Param(name = "self", type = Map.class, doc = "This dict.")},
+      useLocation = true, useEnvironment = true)
   private static Function keys = new NoArgFunction("keys") {
     @Override
     @SuppressWarnings("unchecked") // Skylark will only call this on a dict; and
@@ -592,14 +677,15 @@
     }
   };
 
-  @SkylarkBuiltin(name = "get", objectType = DictModule.class,
+  @SkylarkSignature(name = "get", objectType = DictModule.class,
       doc = "Return the value for <code>key</code> if <code>key</code> is in the dictionary, "
           + "else <code>default</code>. If <code>default</code> is not given, it defaults to "
           + "<code>None</code>, so that this method never throws an error.",
-      mandatoryParams = {
+      mandatoryPositionals = {
+        @Param(name = "self", doc = "This dict."),
         @Param(name = "key", doc = "The key to look for.")},
-      optionalParams = {
-        @Param(name = "default",
+      optionalPositionals = {
+        @Param(name = "default", defaultValue = "None",
             doc = "The default value to use (instead of None) if the key is not found.")})
   private static Function get =
       new MixedModeFunction("get", ImmutableList.of("this", "key", "default"), 2, false) {
@@ -629,7 +715,9 @@
   }
 
   // unary minus
-  @SkylarkBuiltin(name = "-", documented = false, doc = "Unary minus operator.")
+  @SkylarkSignature(name = "-", documented = false, doc = "Unary minus operator.",
+      mandatoryPositionals = {
+        @Param(name = "num", type = Integer.class, doc = "The number to negate.")})
   private static Function minus = new MixedModeFunction("-", ImmutableList.of("this"), 1, false) {
     @Override
     public Object call(Object[] args, FuncallExpression ast) throws ConversionException {
@@ -638,12 +726,13 @@
     }
   };
 
-  @SkylarkBuiltin(name = "list", returnType = SkylarkList.class,
+  @SkylarkSignature(name = "list", returnType = SkylarkList.class,
       doc = "Converts a collection (e.g. set or dictionary) to a list."
         + "<pre class=\"language-python\">list([1, 2]) == [1, 2]\n"
         + "list(set([2, 3, 2])) == [2, 3]\n"
         + "list({5: \"a\", 2: \"b\", 4: \"c\"}) == [2, 4, 5]</pre>",
-      mandatoryParams = {@Param(name = "x", doc = "The object to convert.")})
+      mandatoryPositionals = {@Param(name = "x", doc = "The object to convert.")},
+      useLocation = true)
     private static Function list = new MixedModeFunction("list",
         ImmutableList.of("list"), 1, false) {
     @Override
@@ -653,9 +742,10 @@
     }
   };
 
-  @SkylarkBuiltin(name = "len", returnType = Integer.class, doc =
+  @SkylarkSignature(name = "len", returnType = Integer.class, doc =
       "Returns the length of a string, list, tuple, set, or dictionary.",
-      mandatoryParams = {@Param(name = "x", doc = "The object to check length of.")})
+      mandatoryPositionals = {@Param(name = "x", doc = "The object to check length of.")},
+      useLocation = true)
   private static Function len = new MixedModeFunction("len",
         ImmutableList.of("list"), 1, false) {
 
@@ -671,9 +761,9 @@
     }
   };
 
-  @SkylarkBuiltin(name = "str", returnType = String.class, doc =
+  @SkylarkSignature(name = "str", returnType = String.class, doc =
       "Converts any object to string. This is useful for debugging.",
-      mandatoryParams = {@Param(name = "x", doc = "The object to convert.")})
+      mandatoryPositionals = {@Param(name = "x", doc = "The object to convert.")})
     private static Function str = new MixedModeFunction("str", ImmutableList.of("this"), 1, false) {
     @Override
     public Object call(Object[] args, FuncallExpression ast) throws EvalException {
@@ -681,12 +771,13 @@
     }
   };
 
-  @SkylarkBuiltin(name = "bool", returnType = Boolean.class, doc = "Converts an object to boolean. "
+  @SkylarkSignature(name = "bool", returnType = Boolean.class,
+      doc = "Converts an object to boolean. "
       + "It returns False if the object is None, False, an empty string, the number 0, or an "
       + "empty collection. Otherwise, it returns True. Similarly to Python <code>bool</code> "
       + "is also a type.",
-      mandatoryParams = {@Param(name = "x", doc = "The variable to convert.")})
-      private static Function bool = new MixedModeFunction("bool",
+      mandatoryPositionals = {@Param(name = "x", doc = "The variable to convert.")})
+  private static Function bool = new MixedModeFunction("bool",
           ImmutableList.of("this"), 1, false) {
     @Override
     public Object call(Object[] args, FuncallExpression ast) throws EvalException {
@@ -694,10 +785,12 @@
     }
   };
 
-  @SkylarkBuiltin(name = "int", returnType = Integer.class, doc = "Converts a string to int, "
+  @SkylarkSignature(name = "int", returnType = Integer.class, doc = "Converts a string to int, "
       + "using base 10. It raises an error if the conversion fails."
       + "<pre class=\"language-python\">int(\"123\") == 123</pre>",
-      mandatoryParams = {@Param(name = "x", type = String.class, doc = "The string to convert.")})
+      mandatoryPositionals = {
+        @Param(name = "x", type = String.class, doc = "The string to convert.")},
+      useLocation = true)
   private static Function int_ =
       new MixedModeFunction("int", ImmutableList.of("x"), 1, false) {
         @Override
@@ -713,13 +806,15 @@
         }
       };
 
-  @SkylarkBuiltin(name = "struct", returnType = SkylarkClassObject.class, doc =
+  @SkylarkSignature(name = "struct", returnType = SkylarkClassObject.class, doc =
       "Creates an immutable struct using the keyword arguments as fields. It is used to group "
       + "multiple values together.Example:<br>"
       + "<pre class=\"language-python\">s = struct(x = 2, y = 3)\n"
-      + "return s.x + s.y  # returns 5</pre>")
+      + "return s.x + s.y  # returns 5</pre>",
+      extraKeywords = {
+        @Param(name = "kwarg", doc = "the struct fields")},
+      useLocation = true)
   private static Function struct = new AbstractFunction("struct") {
-
     @Override
     public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
         Environment env) throws EvalException, InterruptedException {
@@ -730,20 +825,21 @@
     }
   };
 
-  @SkylarkBuiltin(name = "set", returnType = SkylarkNestedSet.class,
+  @SkylarkSignature(name = "set", returnType = SkylarkNestedSet.class,
       doc = "Creates a <a href=\"#modules.set\">set</a> from the <code>items</code>."
       + " The set supports nesting other sets of the same element"
       + " type in it. A desired iteration order can also be specified.<br>"
       + " Examples:<br><pre class=\"language-python\">set([\"a\", \"b\"])\n"
       + "set([1, 2, 3], order=\"compile\")</pre>",
-      optionalParams = {
-      @Param(name = "items", type = SkylarkList.class,
-          doc = "The items to initialize the set with. May contain both standalone items and other"
-          + " sets."),
-      @Param(name = "order", type = String.class,
-          doc = "The ordering strategy for the set if it's nested, "
-              + "possible values are: <code>stable</code> (default), <code>compile</code>, "
-              + "<code>link</code> or <code>naive_link</code>.")})
+      optionalPositionals = {
+        @Param(name = "items", type = Object.class, defaultValue = "[]",
+            doc = "The items to initialize the set with. May contain both standalone items "
+            + "and other sets."),
+        @Param(name = "order", type = String.class, defaultValue = "\"stable\"",
+            doc = "The ordering strategy for the set if it's nested, "
+            + "possible values are: <code>stable</code> (default), <code>compile</code>, "
+            + "<code>link</code> or <code>naive_link</code>.")},
+      useLocation = true)
   private static final Function set =
     new MixedModeFunction("set", ImmutableList.of("items", "order"), 0, false) {
     @Override
@@ -757,14 +853,12 @@
     }
   };
 
-  @SkylarkBuiltin(name = "enumerate",  returnType = SkylarkList.class,
+  @SkylarkSignature(name = "enumerate",  returnType = SkylarkList.class,
       doc = "Return a list of pairs (two-element lists), with the index (int) and the item from"
           + " the input list.\n<pre class=\"language-python\">"
           + "enumerate([24, 21, 84]) == [[0, 24], [1, 21], [2, 84]]</pre>\n",
-      mandatoryParams = {
-      @Param(name = "list", type = SkylarkList.class,
-          doc = "input list"),
-      })
+      mandatoryPositionals = {@Param(name = "list", type = SkylarkList.class, doc = "input list")},
+      useLocation = true)
   private static Function enumerate = new MixedModeFunction("enumerate",
       ImmutableList.of("list"), 1, false) {
     @Override
@@ -783,23 +877,25 @@
     }
   };
 
-  @SkylarkBuiltin(name = "range", returnType = SkylarkList.class,
+  @SkylarkSignature(name = "range", returnType = SkylarkList.class,
       doc = "Creates a list where items go from <code>start</code> to <code>stop</code>, using a "
           + "<code>step</code> increment. If a single argument is provided, items will "
           + "range from 0 to that element."
           + "<pre class=\"language-python\">range(4) == [0, 1, 2, 3]\n"
           + "range(3, 9, 2) == [3, 5, 7]\n"
           + "range(3, 0, -1) == [3, 2, 1]</pre>",
-      mandatoryParams = {
-      @Param(name = "start", type = Integer.class,
-          doc = "Value of the first element"),
+      mandatoryPositionals = {
+        @Param(name = "start", type = Integer.class,
+            doc = "Value of the first element if stop is provided, "
+            + "otherwise value of stop and the actual start is 0"),
       },
-      optionalParams = {
-      @Param(name = "stop", type = Integer.class,
-          doc = "The first item <i>not</i> to be included in the resulting list; "
-          + "generation of the list stops before <code>stop</code> is reached."),
-      @Param(name = "step", type = Integer.class,
-          doc = "The increment (default is 1). It may be negative.")})
+      optionalPositionals = {
+        @Param(name = "stop", type = Integer.class, noneable = true,
+            doc = "optional index of the first item <i>not</i> to be included in the "
+            + "resulting list; generation of the list stops before <code>stop</code> is reached."),
+        @Param(name = "step", type = Integer.class,
+            doc = "The increment (default is 1). It may be negative.")},
+      useLocation = true)
   private static final Function range =
     new MixedModeFunction("range", ImmutableList.of("start", "stop", "step"), 1, false) {
     @Override
@@ -838,9 +934,10 @@
    * Returns a function-value implementing "select" (i.e. configurable attributes)
    * in the specified package context.
    */
-  @SkylarkBuiltin(name = "select",
+  @SkylarkSignature(name = "select",
       doc = "Creates a SelectorValue from the dict parameter.",
-      mandatoryParams = {@Param(name = "x", type = Map.class, doc = "The parameter to convert.")})
+      mandatoryPositionals = {
+        @Param(name = "x", type = Map.class, doc = "The parameter to convert.")})
   private static final Function select = new MixedModeFunction("select",
       ImmutableList.of("x"), 1, false) {
       @Override
@@ -858,16 +955,16 @@
   /**
    * Returns true if the object has a field of the given name, otherwise false.
    */
-  @SkylarkBuiltin(name = "hasattr", returnType = Boolean.class,
+  @SkylarkSignature(name = "hasattr", returnType = Boolean.class,
       doc = "Returns True if the object <code>x</code> has a field of the given <code>name</code>, "
           + "otherwise False. Example:<br>"
           + "<pre class=\"language-python\">hasattr(ctx.attr, \"myattr\")</pre>",
-      mandatoryParams = {
-      @Param(name = "object", doc = "The object to check."),
-      @Param(name = "name", type = String.class, doc = "The name of the field.")})
+      mandatoryPositionals = {
+        @Param(name = "object", doc = "The object to check."),
+        @Param(name = "name", type = String.class, doc = "The name of the field.")},
+      useLocation = true, useEnvironment = true)
   private static final Function hasattr =
       new MixedModeFunction("hasattr", ImmutableList.of("object", "name"), 2, false) {
-
     @Override
     public Object call(Object[] args, FuncallExpression ast, Environment env)
         throws EvalException, ConversionException {
@@ -891,19 +988,20 @@
     }
   };
 
-  @SkylarkBuiltin(name = "getattr",
+  @SkylarkSignature(name = "getattr",
       doc = "Returns the struct's field of the given name if exists, otherwise <code>default</code>"
           + " if specified, otherwise rasies an error. For example, <code>getattr(x, \"foobar\")"
           + "</code> is equivalent to <code>x.foobar</code>."
           + "Example:<br>"
           + "<pre class=\"language-python\">getattr(ctx.attr, \"myattr\")\n"
           + "getattr(ctx.attr, \"myattr\", \"mydefault\")</pre>",
-     mandatoryParams = {
-     @Param(name = "object", doc = "The struct which's field is accessed."),
-     @Param(name = "name", doc = "The name of the struct field.")},
-     optionalParams = {
-     @Param(name = "default", doc = "The default value to return in case the struct "
-                                  + "doesn't have a field of the given name.")})
+      mandatoryPositionals = {
+        @Param(name = "object", doc = "The struct which's field is accessed."),
+        @Param(name = "name", doc = "The name of the struct field.")},
+      optionalPositionals = {
+        @Param(name = "default", doc = "The default value to return in case the struct "
+            + "doesn't have a field of the given name.")},
+      useLocation = true)
   private static final Function getattr = new MixedModeFunction(
       "getattr", ImmutableList.of("object", "name", "default"), 2, false) {
     @Override
@@ -924,10 +1022,11 @@
     }
   };
 
-  @SkylarkBuiltin(name = "dir", returnType = SkylarkList.class,
+  @SkylarkSignature(name = "dir", returnType = SkylarkList.class,
       doc = "Returns a list strings: the names of the fields and "
           + "methods of the parameter object.",
-      mandatoryParams = {@Param(name = "object", doc = "The object to check.")})
+      mandatoryPositionals = {@Param(name = "object", doc = "The object to check.")},
+      useLocation = true, useEnvironment = true)
   private static final Function dir = new MixedModeFunction(
       "dir", ImmutableList.of("object"), 1, false) {
     @Override
@@ -950,9 +1049,9 @@
     }
   };
 
-  @SkylarkBuiltin(name = "type", returnType = String.class,
+  @SkylarkSignature(name = "type", returnType = String.class,
       doc = "Returns the type name of its argument.",
-      mandatoryParams = {@Param(name = "object", doc = "The object to check type of.")})
+      mandatoryPositionals = {@Param(name = "object", doc = "The object to check type of.")})
   private static final Function type = new MixedModeFunction("type",
       ImmutableList.of("object"), 1, false) {
     @Override
@@ -962,14 +1061,16 @@
     }
   };
 
-  @SkylarkBuiltin(name = "fail",
+  @SkylarkSignature(name = "fail",
       doc = "Raises an error that cannot be intercepted.",
       returnType = Environment.NoneType.class,
-      mandatoryParams = {
+      mandatoryPositionals = {
         @Param(name = "msg", type = String.class, doc = "Error message to display for the user")},
-      optionalParams = {
-        @Param(name = "attr", type = String.class,
-            doc = "The name of the attribute that caused the error")})
+      optionalPositionals = {
+        @Param(name = "attr", type = String.class, noneable = true,
+            defaultValue = "None",
+            doc = "The name of the attribute that caused the error")},
+      useLocation = true)
   private static final Function fail = new MixedModeFunction(
       "fail", ImmutableList.of("msg", "attr"), 1, false) {
     @Override
@@ -984,13 +1085,14 @@
     }
   };
 
-  @SkylarkBuiltin(name = "print", returnType = Environment.NoneType.class,
+  @SkylarkSignature(name = "print", returnType = Environment.NoneType.class,
       doc = "Prints <code>msg</code> to the console.",
-      mandatoryParams = {
-      @Param(name = "*args", doc = "The objects to print.")},
-      optionalParams = {
-      @Param(name = "sep", type = String.class,
-          doc = "The separator string between the objects, default is space (\" \").")})
+      optionalNamedOnly = {
+        @Param(name = "sep", type = String.class,
+            doc = "The separator string between the objects, default is space (\" \").")},
+      // NB: as compared to Python3, we're missing optional named-only arguments 'end' and 'file'
+      extraPositionals = {@Param(name = "args", doc = "The objects to print.")},
+      useLocation = true, useEnvironment = true)
   private static final Function print = new AbstractFunction("print") {
     @Override
     public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,
@@ -1019,7 +1121,7 @@
     }
   };
 
-  @SkylarkBuiltin(name = "zip",
+  @SkylarkSignature(name = "zip",
       doc = "Returns a <code>list</code> of <code>tuple</code>s, where the i-th tuple contains "
           + "the i-th element from each of the argument sequences or iterables. The list has the "
           + "size of the shortest input. With a single iterable argument, it returns a list of "
@@ -1029,7 +1131,8 @@
           + "zip([1, 2])  # == [(1,), (2,)]\n"
           + "zip([1, 2], [3, 4])  # == [(1, 3), (2, 4)]\n"
           + "zip([1, 2], [3, 4, 5])  # == [(1, 3), (2, 4)]</pre>",
-      returnType = SkylarkList.class)
+      extraPositionals = {@Param(name = "args", doc = "lists to zip")},
+      returnType = SkylarkList.class, useLocation = true)
   private static final Function zip = new AbstractFunction("zip") {
     @Override
     public Object call(List<Object> args, Map<String, Object> kwargs, FuncallExpression ast,