bazel syntax: remove Location from calling convention

This change removes the Location parameter from StarlarkCallable.call
(built-in functions) and the SkylarkCallable.useLocation feature from
annotated built-in functions.

Lately, the thread's call stack records the position of the program
counter of each active frame, so clients may access it through
StarlarkThread.getCallerLocation.

Numerous parameters that pass Locations merely to construct an
EvalException have been deleted. (This is the bulk of the change.)
Many places that directly constructed an EvalException now call
Starlark.errorf instead. (A few places in Bazel formerly specified a
location other than thread.getCallerLocation, or equivalently, null.)
The evaluator ensures that any exception thrown by Starlark.call
is augmented with the location of the call.

PiperOrigin-RevId: 291009378
diff --git a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
index b56e0c3..d52eae2 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/Attribute.java
@@ -35,7 +35,6 @@
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.EventHandler;
-import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassNamePredicate;
 import com.google.devtools.build.lib.packages.Type.ConversionException;
 import com.google.devtools.build.lib.packages.Type.LabelClass;
@@ -1038,13 +1037,11 @@
     @AutoCodec @AutoCodec.VisibleForSerialization
     static final Function<Rule, AspectParameters> EMPTY_FUNCTION = input -> AspectParameters.EMPTY;
 
-    public Builder<TYPE> aspect(SkylarkDefinedAspect skylarkAspect, Location location)
-        throws EvalException {
+    public Builder<TYPE> aspect(SkylarkDefinedAspect skylarkAspect) throws EvalException {
       SkylarkRuleAspect skylarkRuleAspect = new SkylarkRuleAspect(skylarkAspect);
       RuleAspect<?> oldAspect = this.aspects.put(skylarkAspect.getName(), skylarkRuleAspect);
       if (oldAspect != null) {
-        throw new EvalException(
-            location, String.format("aspect %s added more than once", skylarkAspect.getName()));
+        throw Starlark.errorf("aspect %s added more than once", skylarkAspect.getName());
       }
       return this;
     }
@@ -1380,7 +1377,6 @@
   public static final class SkylarkComputedDefaultTemplate {
     private final Type<?> type;
     private final StarlarkCallbackHelper callback;
-    private final Location location;
     private final ImmutableList<String> dependencies;
 
     /**
@@ -1391,19 +1387,14 @@
      * @param dependencies A list of all names of other attributes that are accessed by this
      *     attribute.
      * @param callback A function to compute the actual attribute value.
-     * @param location The location of the Skylark function.
      */
     public SkylarkComputedDefaultTemplate(
-        Type<?> type,
-        ImmutableList<String> dependencies,
-        StarlarkCallbackHelper callback,
-        Location location) {
+        Type<?> type, ImmutableList<String> dependencies, StarlarkCallbackHelper callback) {
       this.type = Preconditions.checkNotNull(type);
       // Order is important for #createDependencyAssignmentTuple.
       this.dependencies =
           Ordering.natural().immutableSortedCopy(Preconditions.checkNotNull(dependencies));
       this.callback = Preconditions.checkNotNull(callback);
-      this.location = Preconditions.checkNotNull(location);
     }
 
     /**
@@ -1494,10 +1485,8 @@
       try {
         return type.cast((result == Starlark.NONE) ? type.getDefaultValue() : result);
       } catch (ClassCastException ex) {
-        throw new EvalException(
-            location,
-            String.format(
-                "expected '%s', but got '%s'", type, EvalUtils.getDataTypeName(result, true)));
+        throw Starlark.errorf(
+            "expected '%s', but got '%s'", type, EvalUtils.getDataTypeName(result, true));
       }
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BuiltinProvider.java b/src/main/java/com/google/devtools/build/lib/packages/BuiltinProvider.java
index 1cd0382..54d92b9 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BuiltinProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/BuiltinProvider.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.packages.NativeProvider.NativeKey;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.Starlark;
 import javax.annotation.Nullable;
 
 /**
@@ -91,12 +92,11 @@
   }
 
   /**
-   * Convenience method for subclasses of this class to throw a consistent error when
-   * a provider is unable to be constructed from skylark.
+   * Convenience method for subclasses of this class to throw a consistent error when a provider is
+   * unable to be constructed from skylark.
    */
-  protected T throwUnsupportedConstructorException(Location loc) throws EvalException {
-    throw new EvalException(
-        loc, String.format("'%s' cannot be constructed from Starlark", getPrintableName()));
+  protected final T throwUnsupportedConstructorException() throws EvalException {
+    throw Starlark.errorf("'%s' cannot be constructed from Starlark", getPrintableName());
   }
 
   /**
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 f6df042..598c33f 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
@@ -108,8 +108,9 @@
       return name;
     }
 
-    private void convertAndProcess(
-        Package.Builder pkgBuilder, Location location, Object value)
+    // The location is used not just for exceptions (for which null would do),
+    // but also for reporting events.
+    private void convertAndProcess(Package.Builder pkgBuilder, Location location, Object value)
         throws EvalException {
       T typedValue = type.convert(value, "'package' argument", pkgBuilder.getBuildFileLabel());
       process(pkgBuilder, location, typedValue);
@@ -515,13 +516,12 @@
       }
 
       @Override
-      public Object call(
-          StarlarkThread thread, Location loc, Tuple<Object> args, Dict<String, Object> kwargs)
+      public Object call(StarlarkThread thread, Tuple<Object> args, Dict<String, Object> kwargs)
           throws EvalException {
         if (!args.isEmpty()) {
           throw new EvalException(null, "unexpected positional arguments");
         }
-        Package.Builder pkgBuilder = getContext(thread, loc).pkgBuilder;
+        Package.Builder pkgBuilder = getContext(thread).pkgBuilder;
 
         // Validate parameter list
         if (pkgBuilder.isPackageFunctionUsed()) {
@@ -534,6 +534,7 @@
           throw new EvalException(
               null, "at least one argument must be given to the 'package' function");
         }
+        Location loc = thread.getCallerLocation();
         for (Map.Entry<String, Object> kwarg : kwargs.entrySet()) {
           String name = kwarg.getKey();
           PackageArgument<?> pkgarg = packageArguments.get(name);
@@ -548,14 +549,12 @@
   }
 
   /** Get the PackageContext by looking up in the environment. */
-  public static PackageContext getContext(StarlarkThread thread, Location location)
-      throws EvalException {
+  public static PackageContext getContext(StarlarkThread thread) throws EvalException {
     PackageContext value = thread.getThreadLocal(PackageContext.class);
     if (value == null) {
       // if PackageContext is missing, we're not called from a BUILD file. This happens if someone
       // uses native.some_func() in the wrong place.
-      throw new EvalException(
-          location,
+      throw Starlark.errorf(
           "The native module can be accessed only from a BUILD thread. "
               + "Wrap the function in a macro and call it from a BUILD file");
     }
@@ -592,29 +591,32 @@
     }
 
     @Override
-    public NoneType call(
-        StarlarkThread thread, Location loc, Tuple<Object> args, Dict<String, Object> kwargs)
+    public NoneType call(StarlarkThread thread, Tuple<Object> args, Dict<String, Object> kwargs)
         throws EvalException, InterruptedException {
       if (!args.isEmpty()) {
-        throw new EvalException(null, "unexpected positional arguments");
+        throw Starlark.errorf("unexpected positional arguments");
       }
       BazelStarlarkContext.from(thread).checkLoadingOrWorkspacePhase(ruleClass.getName());
       try {
-        addRule(getContext(thread, loc), kwargs, loc, thread);
+        addRule(getContext(thread), kwargs, thread);
       } catch (RuleFactory.InvalidRuleException | Package.NameConflictException e) {
-        throw new EvalException(loc, e.getMessage());
+        throw new EvalException(null, e.getMessage());
       }
       return Starlark.NONE;
     }
 
-    private void addRule(
-        PackageContext context, Map<String, Object> kwargs, Location loc, StarlarkThread thread)
+    private void addRule(PackageContext context, Map<String, Object> kwargs, StarlarkThread thread)
         throws RuleFactory.InvalidRuleException, Package.NameConflictException,
             InterruptedException {
       BuildLangTypedAttributeValuesMap attributeValues =
           new BuildLangTypedAttributeValuesMap(kwargs);
       RuleFactory.createAndAddRule(
-          context, ruleClass, attributeValues, loc, thread, new AttributeContainer(ruleClass));
+          context,
+          ruleClass,
+          attributeValues,
+          thread.getCallerLocation(),
+          thread,
+          new AttributeContainer(ruleClass));
     }
 
     @Override
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
index 473df91..780333a 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkAspect.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.packages;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skylarkbuildapi.SkylarkAspectApi;
 import com.google.devtools.build.lib.syntax.EvalException;
 
@@ -26,10 +25,9 @@
    * Attaches this aspect to an attribute.
    *
    * @param attrBuilder the builder of the attribute to add this aspect to
-   * @param loc the location in skylark which adds this aspect to an attribute
    * @throws EvalException if this aspect cannot be successfully applied to the given attribute
    */
-  void attachToAttribute(Attribute.Builder<?> attrBuilder, Location loc) throws EvalException;
+  void attachToAttribute(Attribute.Builder<?> attrBuilder) throws EvalException;
 
   /** Returns the aspect class for this aspect. */
   AspectClass getAspectClass();
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkDefinedAspect.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkDefinedAspect.java
index be38ce1..310ed74 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkDefinedAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkDefinedAspect.java
@@ -20,12 +20,12 @@
 import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
 import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
 import com.google.devtools.build.lib.syntax.BaseFunction;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.Starlark;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -235,13 +235,12 @@
   }
 
   @Override
-  public void attachToAttribute(Attribute.Builder<?> attrBuilder, Location loc)
-      throws EvalException {
+  public void attachToAttribute(Attribute.Builder<?> attrBuilder) throws EvalException {
     if (!isExported()) {
-      throw new EvalException(
-          loc, "Aspects should be top-level values in extension files that define them.");
+      throw Starlark.errorf(
+          "Aspects should be top-level values in extension files that define them.");
     }
-    attrBuilder.aspect(this, loc);
+    attrBuilder.aspect(this);
   }
 
   @Override
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeAspect.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeAspect.java
index c29badc..ee5983c 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeAspect.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeAspect.java
@@ -15,7 +15,6 @@
 package com.google.devtools.build.lib.packages;
 
 import com.google.common.collect.ImmutableSet;
-import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.syntax.Printer;
 
 /** A natively-defined aspect that is may be referenced by skylark attribute definitions. */
@@ -26,7 +25,7 @@
   }
 
   @Override
-  public void attachToAttribute(Attribute.Builder<?> attrBuilder, Location loc) {
+  public void attachToAttribute(Attribute.Builder<?> attrBuilder) {
     attrBuilder.aspect(this);
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
index f267a59..c35e3c8 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkNativeModule.java
@@ -78,11 +78,10 @@
       Sequence<?> exclude,
       Integer excludeDirs,
       Object allowEmptyArgument,
-      Location loc,
       StarlarkThread thread)
       throws EvalException, ConversionException, InterruptedException {
     BazelStarlarkContext.from(thread).checkLoadingPhase("native.glob");
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
 
     List<String> includes = Type.STRING_LIST.convert(include, "'glob' argument");
     List<String> excludes = Type.STRING_LIST.convert(exclude, "'glob' argument");
@@ -94,8 +93,8 @@
     } else if (allowEmptyArgument instanceof Boolean) {
       allowEmpty = (Boolean) allowEmptyArgument;
     } else {
-      throw new EvalException(
-          loc, "expected boolean for argument `allow_empty`, got `" + allowEmptyArgument + "`");
+      throw Starlark.errorf(
+          "expected boolean for argument `allow_empty`, got `%s`", allowEmptyArgument);
     }
 
     try {
@@ -109,25 +108,26 @@
               Joiner.on(", ").join(includes),
               excludes.isEmpty() ? "" : " - [" + Joiner.on(", ").join(excludes) + "]",
               e.getMessage());
+      Location loc = thread.getCallerLocation();
       context.eventHandler.handle(Event.error(loc, errorMessage));
       context.pkgBuilder.setIOExceptionAndMessage(e, errorMessage);
       matches = ImmutableList.of();
     } catch (BadGlobException e) {
-      throw new EvalException(loc, e.getMessage());
+      throw new EvalException(null, e.getMessage());
     } catch (IllegalArgumentException e) {
-      throw new EvalException(loc, "illegal argument in call to glob", e);
+      throw new EvalException(null, "illegal argument in call to glob", e);
     }
 
     return StarlarkList.copyOf(thread.mutability(), matches);
   }
 
   @Override
-  public Object existingRule(String name, Location loc, StarlarkThread thread)
+  public Object existingRule(String name, StarlarkThread thread)
       throws EvalException, InterruptedException {
     BazelStarlarkContext.from(thread).checkLoadingOrWorkspacePhase("native.existing_rule");
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
     Target target = context.pkgBuilder.getTarget(name);
-    Dict<String, Object> rule = targetDict(target, loc, thread.mutability());
+    Dict<String, Object> rule = targetDict(target, thread.mutability());
     return rule != null ? rule : Starlark.NONE;
   }
 
@@ -136,18 +136,18 @@
     For now, we ignore this, since users can implement it in Skylark.
   */
   @Override
-  public Dict<String, Dict<String, Object>> existingRules(Location loc, StarlarkThread thread)
+  public Dict<String, Dict<String, Object>> existingRules(StarlarkThread thread)
       throws EvalException, InterruptedException {
     BazelStarlarkContext.from(thread).checkLoadingOrWorkspacePhase("native.existing_rules");
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
     Collection<Target> targets = context.pkgBuilder.getTargets();
     Mutability mu = thread.mutability();
     Dict<String, Dict<String, Object>> rules = Dict.of(mu);
     for (Target t : targets) {
       if (t instanceof Rule) {
-        Dict<String, Object> rule = targetDict(t, loc, mu);
+        Dict<String, Object> rule = targetDict(t, mu);
         Preconditions.checkNotNull(rule);
-        rules.put(t.getName(), rule, loc);
+        rules.put(t.getName(), rule, (Location) null);
       }
     }
 
@@ -159,11 +159,10 @@
       String name,
       Sequence<?> packagesO,
       Sequence<?> includesO,
-      Location loc,
       StarlarkThread thread)
       throws EvalException {
     BazelStarlarkContext.from(thread).checkLoadingPhase("native.package_group");
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
 
     List<String> packages =
         Type.STRING_LIST.convert(packagesO, "'package_group.packages argument'");
@@ -171,57 +170,51 @@
         BuildType.LABEL_LIST.convert(
             includesO, "'package_group.includes argument'", context.pkgBuilder.getBuildFileLabel());
 
+    Location loc = thread.getCallerLocation();
     try {
       context.pkgBuilder.addPackageGroup(name, packages, includes, context.eventHandler, loc);
       return Starlark.NONE;
     } catch (LabelSyntaxException e) {
-      throw new EvalException(
-          loc, "package group has invalid name: " + name + ": " + e.getMessage());
+      throw Starlark.errorf("package group has invalid name: %s: %s", name, e.getMessage());
     } catch (Package.NameConflictException e) {
-      throw new EvalException(loc, e.getMessage());
+      throw new EvalException(null, e.getMessage());
     }
   }
 
   @Override
   public NoneType exportsFiles(
-      Sequence<?> srcs, Object visibilityO, Object licensesO, Location loc, StarlarkThread thread)
+      Sequence<?> srcs, Object visibilityO, Object licensesO, StarlarkThread thread)
       throws EvalException {
     BazelStarlarkContext.from(thread).checkLoadingPhase("native.exports_files");
-    Package.Builder pkgBuilder = getContext(thread, loc).pkgBuilder;
+    Package.Builder pkgBuilder = getContext(thread).pkgBuilder;
     List<String> files = Type.STRING_LIST.convert(srcs, "'exports_files' operand");
 
-    RuleVisibility visibility;
-    try {
-      visibility =
-          EvalUtils.isNullOrNone(visibilityO)
-              ? ConstantRuleVisibility.PUBLIC
-              : PackageFactory.getVisibility(
-                  pkgBuilder.getBuildFileLabel(),
-                  BuildType.LABEL_LIST.convert(
-                      visibilityO, "'exports_files' operand", pkgBuilder.getBuildFileLabel()));
-    } catch (EvalException e) {
-      throw new EvalException(loc, e.getMessage());
-    }
+    RuleVisibility visibility =
+        EvalUtils.isNullOrNone(visibilityO)
+            ? ConstantRuleVisibility.PUBLIC
+            : PackageFactory.getVisibility(
+                pkgBuilder.getBuildFileLabel(),
+                BuildType.LABEL_LIST.convert(
+                    visibilityO, "'exports_files' operand", pkgBuilder.getBuildFileLabel()));
+
     // TODO(bazel-team): is licenses plural or singular?
     License license = BuildType.LICENSE.convertOptional(licensesO, "'exports_files' operand");
 
+    Location loc = thread.getCallerLocation();
     for (String file : files) {
       String errorMessage = LabelValidator.validateTargetName(file);
       if (errorMessage != null) {
-        throw new EvalException(loc, errorMessage);
+        throw Starlark.errorf("%s", errorMessage);
       }
       try {
         InputFile inputFile = pkgBuilder.createInputFile(file, loc);
         if (inputFile.isVisibilitySpecified() && inputFile.getVisibility() != visibility) {
-          throw new EvalException(
-              loc,
-              String.format(
-                  "visibility for exported file '%s' declared twice", inputFile.getName()));
+          throw Starlark.errorf(
+              "visibility for exported file '%s' declared twice", inputFile.getName());
         }
         if (license != null && inputFile.isLicenseSpecified()) {
-          throw new EvalException(
-              loc,
-              String.format("licenses for exported file '%s' declared twice", inputFile.getName()));
+          throw Starlark.errorf(
+              "licenses for exported file '%s' declared twice", inputFile.getName());
         }
 
         // See if we should check third-party licenses: first checking for any hard-coded policy,
@@ -241,41 +234,38 @@
             && license == null
             && !pkgBuilder.getDefaultLicense().isSpecified()
             && RuleClass.isThirdPartyPackage(pkgBuilder.getPackageIdentifier())) {
-          throw new EvalException(
-              loc,
-              "third-party file '"
-                  + inputFile.getName()
-                  + "' lacks a license declaration "
-                  + "with one of the following types: notice, reciprocal, permissive, "
-                  + "restricted, unencumbered, by_exception_only");
+          throw Starlark.errorf(
+              "third-party file '%s' lacks a license declaration with one of the following types:"
+                  + " notice, reciprocal, permissive, restricted, unencumbered, by_exception_only",
+              inputFile.getName());
         }
 
         pkgBuilder.setVisibilityAndLicense(inputFile, visibility, license);
       } catch (Package.Builder.GeneratedLabelConflict e) {
-        throw new EvalException(loc, e.getMessage());
+        throw Starlark.errorf("%s", e.getMessage());
       }
     }
     return Starlark.NONE;
   }
 
   @Override
-  public String packageName(Location loc, StarlarkThread thread) throws EvalException {
+  public String packageName(StarlarkThread thread) throws EvalException {
     BazelStarlarkContext.from(thread).checkLoadingPhase("native.package_name");
     PackageIdentifier packageId =
-        PackageFactory.getContext(thread, loc).getBuilder().getPackageIdentifier();
+        PackageFactory.getContext(thread).getBuilder().getPackageIdentifier();
     return packageId.getPackageFragment().getPathString();
   }
 
   @Override
-  public String repositoryName(Location location, StarlarkThread thread) throws EvalException {
+  public String repositoryName(StarlarkThread thread) throws EvalException {
     BazelStarlarkContext.from(thread).checkLoadingPhase("native.repository_name");
     PackageIdentifier packageId =
-        PackageFactory.getContext(thread, location).getBuilder().getPackageIdentifier();
+        PackageFactory.getContext(thread).getBuilder().getPackageIdentifier();
     return packageId.getRepository().toString();
   }
 
   @Nullable
-  private static Dict<String, Object> targetDict(Target target, Location loc, Mutability mu)
+  private static Dict<String, Object> targetDict(Target target, Mutability mu)
       throws EvalException {
     if (!(target instanceof Rule)) {
       return null;
@@ -300,7 +290,7 @@
         if (val == null) {
           continue;
         }
-        values.put(attr.getName(), val, loc);
+        values.put(attr.getName(), val, (Location) null);
       } catch (NotRepresentableException e) {
         throw new NotRepresentableException(
             String.format(
@@ -308,8 +298,8 @@
       }
     }
 
-    values.put("name", rule.getName(), loc);
-    values.put("kind", rule.getRuleClass(), loc);
+    values.put("name", rule.getName(), (Location) null);
+    values.put("kind", rule.getRuleClass(), (Location) null);
     return values;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java b/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
index d8ccc30..95a17c3 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/SkylarkProvider.java
@@ -149,13 +149,14 @@
   }
 
   @Override
-  public Object fastcall(StarlarkThread thread, Location loc, Object[] positional, Object[] named)
+  public Object fastcall(StarlarkThread thread, Object[] positional, Object[] named)
       throws EvalException, InterruptedException {
     // TODO(adonovan): we can likely come up with a more efficient implementation
     // ...then make matchSignature private again?
     Object[] arguments =
         Starlark.matchSignature(
             signature, this, /*defaults=*/ null, thread.mutability(), positional, named);
+    Location loc = thread.getCallerLocation();
     if (fields == null) {
       // provider(**kwargs)
       @SuppressWarnings("unchecked")
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java
index f8ee7c8..ce9afaf 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkBuildLibrary.java
@@ -85,16 +85,14 @@
       // Not documented by docgen, as this is only available in BUILD files.
       // TODO(cparsons): Devise a solution to document BUILD functions.
       documented = false,
-      useLocation = true,
       useStarlarkThread = true)
   public NoneType environmentGroup(
       String name,
       Sequence<?> environmentsList, // <Label>
       Sequence<?> defaultsList, // <Label>
-      Location loc,
       StarlarkThread thread)
       throws EvalException {
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
     List<Label> environments =
         BuildType.LABEL_LIST.convert(
             environmentsList,
@@ -105,18 +103,17 @@
             defaultsList, "'environment_group argument'", context.pkgBuilder.getBuildFileLabel());
 
     if (environments.isEmpty()) {
-      throw new EvalException(
-          loc, "environment group " + name + " must contain at least one environment");
+      throw Starlark.errorf("environment group %s must contain at least one environment", name);
     }
     try {
+      Location loc = thread.getCallerLocation();
       context.pkgBuilder.addEnvironmentGroup(
           name, environments, defaults, context.eventHandler, loc);
       return Starlark.NONE;
     } catch (LabelSyntaxException e) {
-      throw new EvalException(
-          loc, "environment group has invalid name: " + name + ": " + e.getMessage());
+      throw Starlark.errorf("environment group has invalid name: %s: %s", name, e.getMessage());
     } catch (Package.NameConflictException e) {
-      throw new EvalException(loc, e.getMessage());
+      throw Starlark.errorf("%s", e.getMessage());
     }
   }
 
@@ -133,19 +130,17 @@
       // Not documented by docgen, as this is only available in BUILD files.
       // TODO(cparsons): Devise a solution to document BUILD functions.
       documented = false,
-      useStarlarkThread = true,
-      useLocation = true)
+      useStarlarkThread = true)
   public NoneType licenses(
       Sequence<?> licensesList, // list of license strings
-      Location loc,
       StarlarkThread thread)
       throws EvalException {
-    PackageContext context = getContext(thread, loc);
+    PackageContext context = getContext(thread);
     try {
       License license = BuildType.LICENSE.convert(licensesList, "'licenses' operand");
       context.pkgBuilder.setDefaultLicense(license);
     } catch (ConversionException e) {
-      context.eventHandler.handle(Event.error(loc, e.getMessage()));
+      context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
       context.pkgBuilder.setContainsErrors();
     }
     return Starlark.NONE;
@@ -160,18 +155,16 @@
       // Not documented by docgen, as this is only available in BUILD files.
       // TODO(cparsons): Devise a solution to document BUILD functions.
       documented = false,
-      useStarlarkThread = true,
-      useLocation = true)
-  public NoneType distribs(Object object, Location loc, StarlarkThread thread)
-      throws EvalException {
-    PackageContext context = getContext(thread, loc);
+      useStarlarkThread = true)
+  public NoneType distribs(Object object, StarlarkThread thread) throws EvalException {
+    PackageContext context = getContext(thread);
 
     try {
       Set<DistributionType> distribs =
           BuildType.DISTRIBUTIONS.convert(object, "'distribs' operand");
       context.pkgBuilder.setDefaultDistribs(distribs);
     } catch (ConversionException e) {
-      context.eventHandler.handle(Event.error(loc, e.getMessage()));
+      context.eventHandler.handle(Event.error(thread.getCallerLocation(), e.getMessage()));
       context.pkgBuilder.setContainsErrors();
     }
     return Starlark.NONE;
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java b/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
index 845c677..0b0cc35 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StructImpl.java
@@ -170,34 +170,34 @@
   }
 
   @Override
-  public String toProto(Location loc) throws EvalException {
+  public String toProto() throws EvalException {
     StringBuilder sb = new StringBuilder();
-    printProtoTextMessage(this, sb, 0, loc);
+    printProtoTextMessage(this, sb, 0);
     return sb.toString();
   }
 
-  private void printProtoTextMessage(ClassObject object, StringBuilder sb, int indent, Location loc)
+  private static void printProtoTextMessage(ClassObject object, StringBuilder sb, int indent)
       throws EvalException {
     // For determinism sort the fields alphabetically.
     List<String> fields = new ArrayList<>(object.getFieldNames());
     Collections.sort(fields);
     for (String field : fields) {
-      printProtoTextMessage(field, object.getValue(field), sb, indent, loc);
+      printProtoTextMessage(field, object.getValue(field), sb, indent);
     }
   }
 
-  private void printProtoTextMessage(
-      String key, Object value, StringBuilder sb, int indent, Location loc, String container)
+  private static void printProtoTextMessage(
+      String key, Object value, StringBuilder sb, int indent, String container)
       throws EvalException {
     if (value instanceof Map.Entry) {
       Map.Entry<?, ?> entry = (Map.Entry<?, ?>) value;
       print(sb, key + " {", indent);
-      printProtoTextMessage("key", entry.getKey(), sb, indent + 1, loc);
-      printProtoTextMessage("value", entry.getValue(), sb, indent + 1, loc);
+      printProtoTextMessage("key", entry.getKey(), sb, indent + 1);
+      printProtoTextMessage("value", entry.getValue(), sb, indent + 1);
       print(sb, "}", indent);
     } else if (value instanceof ClassObject) {
       print(sb, key + " {", indent);
-      printProtoTextMessage((ClassObject) value, sb, indent + 1, loc);
+      printProtoTextMessage((ClassObject) value, sb, indent + 1);
       print(sb, "}", indent);
     } else if (value instanceof String) {
       print(
@@ -211,36 +211,31 @@
       // as the protocol buffers do.
       print(sb, key + ": " + value, indent);
     } else {
-      throw new EvalException(
-          loc,
-          "Invalid text format, expected a struct, a dict, a string, a bool, or an int but got a "
-              + EvalUtils.getDataTypeName(value)
-              + " for "
-              + container
-              + " '"
-              + key
-              + "'");
+      throw Starlark.errorf(
+          "Invalid text format, expected a struct, a dict, a string, a bool, or an int but got a"
+              + " %s for %s '%s'",
+          EvalUtils.getDataTypeName(value), container, key);
     }
   }
 
-  private void printProtoTextMessage(
-      String key, Object value, StringBuilder sb, int indent, Location loc) throws EvalException {
+  private static void printProtoTextMessage(String key, Object value, StringBuilder sb, int indent)
+      throws EvalException {
     if (value instanceof Sequence) {
       for (Object item : ((Sequence) value)) {
         // TODO(bazel-team): There should be some constraint on the fields of the structs
         // in the same list but we ignore that for now.
-        printProtoTextMessage(key, item, sb, indent, loc, "list element in struct field");
+        printProtoTextMessage(key, item, sb, indent, "list element in struct field");
       }
     } else if (value instanceof Dict) {
       for (Map.Entry<?, ?> entry : ((Dict<?, ?>) value).entrySet()) {
-        printProtoTextMessage(key, entry, sb, indent, loc, "entry of dictionary");
+        printProtoTextMessage(key, entry, sb, indent, "entry of dictionary");
       }
     } else {
-      printProtoTextMessage(key, value, sb, indent, loc, "struct field");
+      printProtoTextMessage(key, value, sb, indent, "struct field");
     }
   }
 
-  private void print(StringBuilder sb, String text, int indent) {
+  private static void print(StringBuilder sb, String text, int indent) {
     for (int i = 0; i < indent; i++) {
       sb.append("  ");
     }
@@ -258,13 +253,13 @@
   }
 
   @Override
-  public String toJson(Location loc) throws EvalException {
+  public String toJson() throws EvalException {
     StringBuilder sb = new StringBuilder();
-    printJson(this, sb, loc, "struct field", null);
+    printJson(this, sb, "struct field", null);
     return sb.toString();
   }
 
-  private void printJson(Object value, StringBuilder sb, Location loc, String container, String key)
+  private static void printJson(Object value, StringBuilder sb, String container, String key)
       throws EvalException {
     if (value == Starlark.NONE) {
       sb.append("null");
@@ -278,7 +273,7 @@
         sb.append("\"");
         sb.append(field);
         sb.append("\":");
-        printJson(((ClassObject) value).getValue(field), sb, loc, "struct field", field);
+        printJson(((ClassObject) value).getValue(field), sb, "struct field", field);
       }
       sb.append("}");
     } else if (value instanceof Dict) {
@@ -288,20 +283,16 @@
         sb.append(join);
         join = ",";
         if (!(entry.getKey() instanceof String)) {
-          String errorMessage =
-              "Keys must be a string but got a "
-                  + EvalUtils.getDataTypeName(entry.getKey())
-                  + " for "
-                  + container;
-          if (key != null) {
-            errorMessage += " '" + key + "'";
-          }
-          throw new EvalException(loc, errorMessage);
+          throw Starlark.errorf(
+              "Keys must be a string but got a %s for %s%s",
+              EvalUtils.getDataTypeName(entry.getKey()),
+              container,
+              key != null ? " '" + key + "'" : "");
         }
         sb.append("\"");
         sb.append(entry.getKey());
         sb.append("\":");
-        printJson(entry.getValue(), sb, loc, "dict value", String.valueOf(entry.getKey()));
+        printJson(entry.getValue(), sb, "dict value", String.valueOf(entry.getKey()));
       }
       sb.append("}");
     } else if (value instanceof List) {
@@ -310,7 +301,7 @@
       for (Object item : ((List) value)) {
         sb.append(join);
         join = ",";
-        printJson(item, sb, loc, "list element in struct field", key);
+        printJson(item, sb, "list element in struct field", key);
       }
       sb.append("]");
     } else if (value instanceof String) {
@@ -320,20 +311,14 @@
     } else if (value instanceof Integer || value instanceof Boolean) {
       sb.append(value);
     } else {
-      String errorMessage =
-          "Invalid text format, expected a struct, a string, a bool, or an int "
-              + "but got a "
-              + EvalUtils.getDataTypeName(value)
-              + " for "
-              + container;
-      if (key != null) {
-        errorMessage += " '" + key + "'";
-      }
-      throw new EvalException(loc, errorMessage);
+      throw Starlark.errorf(
+          "Invalid text format, expected a struct, a string, a bool, or an int but got a %s for"
+              + " %s%s",
+          EvalUtils.getDataTypeName(value), container, key != null ? " '" + key + "'" : "");
     }
   }
 
-  private String jsonEscapeString(String string) {
+  private static String jsonEscapeString(String string) {
     return escapeDoubleQuotesAndBackslashesAndNewlines(string)
         .replace("\r", "\\r")
         .replace("\t", "\\t");
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StructProvider.java b/src/main/java/com/google/devtools/build/lib/packages/StructProvider.java
index 998f632..ca75eb8 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StructProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StructProvider.java
@@ -18,6 +18,8 @@
 import com.google.devtools.build.lib.skylarkbuildapi.core.StructApi;
 import com.google.devtools.build.lib.syntax.Dict;
 import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.Starlark;
+import com.google.devtools.build.lib.syntax.StarlarkThread;
 import java.util.Map;
 
 /**
@@ -36,26 +38,34 @@
   }
 
   @Override
-  public StructImpl createStruct(Dict<?, ?> kwargs, Location loc) throws EvalException {
-    Map<String, Object> kwargsMap = kwargs.getContents(String.class, Object.class, "kwargs");
-    if (kwargsMap.containsKey("to_json")) {
-      throw new EvalException(loc, "cannot override built-in struct function 'to_json'");
+  public StructImpl createStruct(Dict<String, Object> kwargs, StarlarkThread thread)
+      throws EvalException {
+    return create(kwargs, thread.getCallerLocation());
+  }
+
+  // Called from SkylarkRepositoryContext. TODO(adonovan): eliminate.
+  public StructImpl createWithBuiltinLocation(Dict<String, Object> kwargs) throws EvalException {
+    return create(kwargs, Location.BUILTIN);
+  }
+
+  private StructImpl create(Dict<String, Object> kwargs, Location location) throws EvalException {
+    if (kwargs.containsKey("to_json")) {
+      throw Starlark.errorf("cannot override built-in struct function 'to_json'");
     }
-    if (kwargsMap.containsKey("to_proto")) {
-      throw new EvalException(loc, "cannot override built-in struct function 'to_proto'");
+    if (kwargs.containsKey("to_proto")) {
+      throw Starlark.errorf("cannot override built-in struct function 'to_proto'");
     }
-    return SkylarkInfo.create(this, kwargsMap, loc);
+    return SkylarkInfo.create(this, kwargs, location);
   }
 
   /**
    * Creates a struct with the given field values and message format for unknown fields.
    *
    * <p>The custom message is useful for objects that have fields but aren't exactly used as
-   * providers, such as the {@code native} object, and the struct fields of {@code ctx} like
-   * {@code ctx.attr}.
-   * */
-  public SkylarkInfo create(
-      Map<String, Object> values, String errorMessageFormatForUnknownField) {
+   * providers, such as the {@code native} object, and the struct fields of {@code ctx} like {@code
+   * ctx.attr}.
+   */
+  public SkylarkInfo create(Map<String, Object> values, String errorMessageFormatForUnknownField) {
     return SkylarkInfo.createWithCustomMessage(this, values, errorMessageFormatForUnknownField);
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
index 656dfbe..f59f28e 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceFactory.java
@@ -274,14 +274,13 @@
       }
 
       @Override
-      public Object call(
-          StarlarkThread thread, Location loc, Tuple<Object> args, Dict<String, Object> kwargs)
+      public Object call(StarlarkThread thread, Tuple<Object> args, Dict<String, Object> kwargs)
           throws EvalException, InterruptedException {
         if (!args.isEmpty()) {
           throw new EvalException(null, "unexpected positional arguments");
         }
         try {
-          Package.Builder builder = PackageFactory.getContext(thread, loc).pkgBuilder;
+          Package.Builder builder = PackageFactory.getContext(thread).pkgBuilder;
           // TODO(adonovan): this doesn't look safe!
           String externalRepoName = (String) kwargs.get("name");
           if (!allowOverride
@@ -298,6 +297,7 @@
           // @<mainRepoName> as a separate repository. This will be overridden if the main
           // repository has a repo_mapping entry from <mainRepoName> to something.
           WorkspaceFactoryHelper.addMainRepoEntry(builder, externalRepoName, thread.getSemantics());
+          Location loc = thread.getCallerLocation();
           WorkspaceFactoryHelper.addRepoMappings(builder, kwargs, externalRepoName, loc);
           RuleClass ruleClass = ruleFactory.getRuleClass(ruleClassName);
           RuleClass bindRuleClass = ruleFactory.getRuleClass("bind");
diff --git a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceGlobals.java b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceGlobals.java
index cabe2c1..c7658b4 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/WorkspaceGlobals.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/WorkspaceGlobals.java
@@ -27,7 +27,6 @@
 import com.google.devtools.build.lib.cmdline.LabelValidator;
 import com.google.devtools.build.lib.cmdline.RepositoryName;
 import com.google.devtools.build.lib.cmdline.TargetPattern;
-import com.google.devtools.build.lib.events.Location;
 import com.google.devtools.build.lib.packages.Package.NameConflictException;
 import com.google.devtools.build.lib.packages.RuleFactory.InvalidRuleException;
 import com.google.devtools.build.lib.skylarkbuildapi.WorkspaceGlobalsApi;
@@ -35,6 +34,7 @@
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.syntax.NoneType;
 import com.google.devtools.build.lib.syntax.Sequence;
+import com.google.devtools.build.lib.syntax.Starlark;
 import com.google.devtools.build.lib.syntax.StarlarkThread;
 import com.google.devtools.build.lib.vfs.PathFragment;
 import java.util.List;
@@ -69,19 +69,18 @@
   public NoneType workspace(
       String name,
       Dict<?, ?> managedDirectories, // <String, Object>
-      Location loc,
       StarlarkThread thread)
       throws EvalException, InterruptedException {
     if (allowOverride) {
       if (!isLegalWorkspaceName(name)) {
-        throw new EvalException(loc, name + " is not a legal workspace name");
+        throw Starlark.errorf("%s is not a legal workspace name", name);
       }
       String errorMessage = LabelValidator.validateTargetName(name);
       if (errorMessage != null) {
-        throw new EvalException(loc, errorMessage);
+        throw Starlark.errorf("%s", errorMessage);
       }
-      PackageFactory.getContext(thread, loc).pkgBuilder.setWorkspaceName(name);
-      Package.Builder builder = PackageFactory.getContext(thread, loc).pkgBuilder;
+      PackageFactory.getContext(thread).pkgBuilder.setWorkspaceName(name);
+      Package.Builder builder = PackageFactory.getContext(thread).pkgBuilder;
       RuleClass localRepositoryRuleClass = ruleFactory.getRuleClass("local_repository");
       RuleClass bindRuleClass = ruleFactory.getRuleClass("bind");
       Map<String, Object> kwargs = ImmutableMap.<String, Object>of("name", name, "path", ".");
@@ -89,9 +88,9 @@
         // This effectively adds a "local_repository(name = "<ws>", path = ".")"
         // definition to the WORKSPACE file.
         WorkspaceFactoryHelper.createAndAddRepositoryRule(
-            builder, localRepositoryRuleClass, bindRuleClass, kwargs, loc);
+            builder, localRepositoryRuleClass, bindRuleClass, kwargs, thread.getCallerLocation());
       } catch (InvalidRuleException | NameConflictException | LabelSyntaxException e) {
-        throw new EvalException(loc, e.getMessage());
+        throw Starlark.errorf("%s", e.getMessage());
       }
       // Add entry in repository map from "@name" --> "@" to avoid issue where bazel
       // treats references to @name as a separate external repo
@@ -100,51 +99,42 @@
           RepositoryName.createFromValidStrippedName(name),
           RepositoryName.MAIN);
       parseManagedDirectories(
-          managedDirectories.getContents(String.class, Object.class, "managed_directories"), loc);
+          managedDirectories.getContents(String.class, Object.class, "managed_directories"));
       return NONE;
     } else {
-      throw new EvalException(
-          loc, "workspace() function should be used only at the top of the WORKSPACE file");
+      throw Starlark.errorf(
+          "workspace() function should be used only at the top of the WORKSPACE file");
     }
   }
 
   @Override
-  public NoneType dontSymlinkDirectoriesInExecroot(
-      Sequence<?> paths, Location location, StarlarkThread thread)
+  public NoneType dontSymlinkDirectoriesInExecroot(Sequence<?> paths, StarlarkThread thread)
       throws EvalException, InterruptedException {
     List<String> pathsList = paths.getContents(String.class, "paths");
     Set<String> set = Sets.newHashSet();
     for (String path : pathsList) {
       PathFragment pathFragment = PathFragment.create(path);
       if (pathFragment.isEmpty()) {
-        throw new EvalException(
-            location, "Empty path can not be passed to dont_symlink_directories_in_execroot.");
+        throw Starlark.errorf(
+            "Empty path can not be passed to dont_symlink_directories_in_execroot.");
       }
       if (pathFragment.containsUplevelReferences() || pathFragment.segmentCount() > 1) {
-        throw new EvalException(
-            location,
-            String.format(
-                "dont_symlink_directories_in_execroot can only accept "
-                    + "top level directories under workspace, "
-                    + "\"%s\" can not be specified as an attribute.",
-                path));
+        throw Starlark.errorf(
+            "dont_symlink_directories_in_execroot can only accept top level directories under"
+                + " workspace, \"%s\" can not be specified as an attribute.",
+            path);
       }
       if (pathFragment.isAbsolute()) {
-        throw new EvalException(
-            location,
-            String.format(
-                "dont_symlink_directories_in_execroot can only accept "
-                    + "top level directories under workspace, "
-                    + "absolute path \"%s\" can not be specified as an attribute.",
-                path));
+        throw Starlark.errorf(
+            "dont_symlink_directories_in_execroot can only accept top level directories under"
+                + " workspace, absolute path \"%s\" can not be specified as an attribute.",
+            path);
       }
       if (!set.add(pathFragment.getBaseName())) {
-        throw new EvalException(
-            location,
-            String.format(
-                "dont_symlink_directories_in_execroot should not "
-                    + "contain duplicate values: \"%s\" is specified more then once.",
-                path));
+        throw Starlark.errorf(
+            "dont_symlink_directories_in_execroot should not contain duplicate values: \"%s\" is"
+                + " specified more then once.",
+            path);
       }
     }
     doNotSymlinkInExecrootPaths = ImmutableSortedSet.copyOf(set);
@@ -152,89 +142,72 @@
   }
 
   private void parseManagedDirectories(
-      Map<String, ?> managedDirectories, // <String, Sequence<String>>
-      Location loc)
+      Map<String, ?> managedDirectories) // <String, Sequence<String>>
       throws EvalException {
     Map<PathFragment, String> nonNormalizedPathsMap = Maps.newHashMap();
     for (Map.Entry<String, ?> entry : managedDirectories.entrySet()) {
-      RepositoryName repositoryName = createRepositoryName(entry.getKey(), loc);
+      RepositoryName repositoryName = createRepositoryName(entry.getKey());
       List<PathFragment> paths =
-          getManagedDirectoriesPaths(entry.getValue(), loc, nonNormalizedPathsMap);
+          getManagedDirectoriesPaths(entry.getValue(), nonNormalizedPathsMap);
       for (PathFragment dir : paths) {
         PathFragment floorKey = managedDirectoriesMap.floorKey(dir);
         if (dir.equals(floorKey)) {
-          throw new EvalException(
-              loc,
-              String.format(
-                  "managed_directories attribute should not contain multiple"
-                      + " (or duplicate) repository mappings for the same directory ('%s').",
-                  nonNormalizedPathsMap.get(dir)));
+          throw Starlark.errorf(
+              "managed_directories attribute should not contain multiple"
+                  + " (or duplicate) repository mappings for the same directory ('%s').",
+              nonNormalizedPathsMap.get(dir));
         }
         PathFragment ceilingKey = managedDirectoriesMap.ceilingKey(dir);
         boolean isDescendant = floorKey != null && dir.startsWith(floorKey);
         if (isDescendant || (ceilingKey != null && ceilingKey.startsWith(dir))) {
-          throw new EvalException(
-              loc,
-              String.format(
-                  "managed_directories attribute value can not contain nested mappings."
-                      + " '%s' is a descendant of '%s'.",
-                  nonNormalizedPathsMap.get(isDescendant ? dir : ceilingKey),
-                  nonNormalizedPathsMap.get(isDescendant ? floorKey : dir)));
+          throw Starlark.errorf(
+              "managed_directories attribute value can not contain nested mappings."
+                  + " '%s' is a descendant of '%s'.",
+              nonNormalizedPathsMap.get(isDescendant ? dir : ceilingKey),
+              nonNormalizedPathsMap.get(isDescendant ? floorKey : dir));
         }
         managedDirectoriesMap.put(dir, repositoryName);
       }
     }
   }
 
-  private static RepositoryName createRepositoryName(String key, Location location)
-      throws EvalException {
+  private static RepositoryName createRepositoryName(String key) throws EvalException {
     if (!key.startsWith("@")) {
-      throw new EvalException(
-          location,
-          String.format(
-              "Cannot parse repository name '%s'. Repository name should start with '@'.", key));
+      throw Starlark.errorf(
+          "Cannot parse repository name '%s'. Repository name should start with '@'.", key);
     }
     try {
       return RepositoryName.create(key);
     } catch (LabelSyntaxException e) {
-      throw new EvalException(location, e);
+      throw Starlark.errorf("%s", e);
     }
   }
 
   private static List<PathFragment> getManagedDirectoriesPaths(
-      Object directoriesList, Location location, Map<PathFragment, String> nonNormalizedPathsMap)
+      Object directoriesList, Map<PathFragment, String> nonNormalizedPathsMap)
       throws EvalException {
     if (!(directoriesList instanceof Sequence)) {
-      throw new EvalException(
-          location,
+      throw Starlark.errorf(
           "managed_directories attribute value should be of the type attr.string_list_dict(),"
               + " mapping repository name to the list of managed directories.");
     }
     List<PathFragment> result = Lists.newArrayList();
     for (Object obj : (Sequence) directoriesList) {
       if (!(obj instanceof String)) {
-        throw new EvalException(
-            location,
-            String.format("Expected managed directory path (as string), but got '%s'.", obj));
+        throw Starlark.errorf("Expected managed directory path (as string), but got '%s'.", obj);
       }
       String path = ((String) obj).trim();
       if (path.isEmpty()) {
-        throw new EvalException(
-            location, "Expected managed directory path to be non-empty string.");
+        throw Starlark.errorf("Expected managed directory path to be non-empty string.");
       }
       PathFragment pathFragment = PathFragment.create(path);
       if (pathFragment.isAbsolute()) {
-        throw new EvalException(
-            location,
-            String.format(
-                "Expected managed directory path ('%s') to be relative to the workspace root.",
-                path));
+        throw Starlark.errorf(
+            "Expected managed directory path ('%s') to be relative to the workspace root.", path);
       }
       if (pathFragment.containsUplevelReferences()) {
-        throw new EvalException(
-            location,
-            String.format(
-                "Expected managed directory path ('%s') to be under the workspace root.", path));
+        throw Starlark.errorf(
+            "Expected managed directory path ('%s') to be under the workspace root.", path);
       }
       nonNormalizedPathsMap.put(pathFragment, path);
       result.add(pathFragment);
@@ -270,52 +243,50 @@
   }
 
   @Override
-  public NoneType registerExecutionPlatforms(
-      Sequence<?> platformLabels, Location location, StarlarkThread thread)
+  public NoneType registerExecutionPlatforms(Sequence<?> platformLabels, StarlarkThread thread)
       throws EvalException, InterruptedException {
     // Add to the package definition for later.
-    Package.Builder builder = PackageFactory.getContext(thread, location).pkgBuilder;
+    Package.Builder builder = PackageFactory.getContext(thread).pkgBuilder;
     List<String> patterns = platformLabels.getContents(String.class, "platform_labels");
     builder.addRegisteredExecutionPlatforms(renamePatterns(patterns, builder, thread));
     return NONE;
   }
 
   @Override
-  public NoneType registerToolchains(
-      Sequence<?> toolchainLabels, Location location, StarlarkThread thread)
+  public NoneType registerToolchains(Sequence<?> toolchainLabels, StarlarkThread thread)
       throws EvalException, InterruptedException {
     // Add to the package definition for later.
-    Package.Builder builder = PackageFactory.getContext(thread, location).pkgBuilder;
+    Package.Builder builder = PackageFactory.getContext(thread).pkgBuilder;
     List<String> patterns = toolchainLabels.getContents(String.class, "toolchain_labels");
     builder.addRegisteredToolchains(renamePatterns(patterns, builder, thread));
     return NONE;
   }
 
   @Override
-  public NoneType bind(String name, Object actual, Location loc, StarlarkThread thread)
+  public NoneType bind(String name, Object actual, StarlarkThread thread)
       throws EvalException, InterruptedException {
     Label nameLabel;
     try {
       nameLabel = Label.parseAbsolute("//external:" + name, ImmutableMap.of());
-      try {
-        Package.Builder builder = PackageFactory.getContext(thread, loc).pkgBuilder;
-        RuleClass ruleClass = ruleFactory.getRuleClass("bind");
-        WorkspaceFactoryHelper.addBindRule(
-            builder,
-            ruleClass,
-            nameLabel,
-            actual == NONE ? null : Label.parseAbsolute((String) actual, ImmutableMap.of()),
-            loc,
-            new AttributeContainer(ruleClass));
-      } catch (RuleFactory.InvalidRuleException
-          | Package.NameConflictException
-          | LabelSyntaxException e) {
-        throw new EvalException(loc, e.getMessage());
-      }
-
     } catch (LabelSyntaxException e) {
-      throw new EvalException(loc, e.getMessage());
+      throw Starlark.errorf("%s", e.getMessage());
     }
+    try {
+      Package.Builder builder = PackageFactory.getContext(thread).pkgBuilder;
+      RuleClass ruleClass = ruleFactory.getRuleClass("bind");
+      WorkspaceFactoryHelper.addBindRule(
+          builder,
+          ruleClass,
+          nameLabel,
+          actual == NONE ? null : Label.parseAbsolute((String) actual, ImmutableMap.of()),
+          thread.getCallerLocation(),
+          new AttributeContainer(ruleClass));
+    } catch (RuleFactory.InvalidRuleException
+        | Package.NameConflictException
+        | LabelSyntaxException e) {
+      throw Starlark.errorf("%s", e.getMessage());
+    }
+
     return NONE;
   }