Refactor util function, improve error message

RELNOTES: None
PiperOrigin-RevId: 303848271
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java
index bf397b5..e1da7da 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/ResolvedToolchainContext.java
@@ -166,7 +166,7 @@
       try {
         return Label.parseAbsolute((String) key, repoMapping);
       } catch (LabelSyntaxException e) {
-        throw Starlark.errorf("Unable to parse toolchain %s: %s", key, e.getMessage());
+        throw Starlark.errorf("Unable to parse toolchain label '%s': %s", key, e.getMessage());
       }
     } else {
       throw Starlark.errorf(
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
index 0667618..c1b76d8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/skylark/SkylarkRuleClassFunctions.java
@@ -365,9 +365,7 @@
         (Label) Module.ofInnermostEnclosingStarlarkFunction(thread).getLabel(),
         thread.getTransitiveContentHashCode());
 
-    builder.addRequiredToolchains(
-        collectToolchainLabels(
-            toolchains.getContents(String.class, "toolchains"), bazelContext.getRepoMapping()));
+    builder.addRequiredToolchains(parseToolchains(toolchains, thread));
 
     if (!buildSetting.equals(Starlark.NONE) && !cfg.equals(Starlark.NONE)) {
       throw Starlark.errorf(
@@ -401,10 +399,7 @@
     }
 
     if (!execCompatibleWith.isEmpty()) {
-      builder.addExecutionPlatformConstraints(
-          collectConstraintLabels(
-              execCompatibleWith.getContents(String.class, "exec_compatile_with"),
-              bazelContext.getRepoMapping()));
+      builder.addExecutionPlatformConstraints(parseExecCompatibleWith(execCompatibleWith, thread));
     }
 
     return new SkylarkRuleFunction(builder, type, attributes, thread.getCallerLocation());
@@ -442,37 +437,46 @@
     }
   }
 
-  private static ImmutableList<Label> collectToolchainLabels(
-      Iterable<String> rawLabels, ImmutableMap<RepositoryName, RepositoryName> mapping)
+  /**
+   * Parses a sequence of label strings with a repo mapping.
+   *
+   * @param inputs sequence of input strings
+   * @param mapping repository mapping
+   * @param adjective describes the purpose of the label; used for errors
+   * @throws EvalException if the label can't be parsed
+   */
+  private static ImmutableList<Label> parseLabels(
+      Iterable<String> inputs,
+      ImmutableMap<RepositoryName, RepositoryName> mapping,
+      String adjective)
       throws EvalException {
-    ImmutableList.Builder<Label> requiredToolchains = new ImmutableList.Builder<>();
-    for (String rawLabel : rawLabels) {
+    ImmutableList.Builder<Label> parsedLabels = new ImmutableList.Builder<>();
+    for (String input : inputs) {
       try {
-        Label toolchainLabel = Label.parseAbsolute(rawLabel, mapping);
-        requiredToolchains.add(toolchainLabel);
+        Label label = Label.parseAbsolute(input, mapping);
+        parsedLabels.add(label);
       } catch (LabelSyntaxException e) {
-        throw new EvalException(
-            null, String.format("Unable to parse toolchain %s: %s", rawLabel, e.getMessage()), e);
+        throw Starlark.errorf(
+            "Unable to parse %s label '%s': %s", adjective, input, e.getMessage());
       }
     }
-
-    return requiredToolchains.build();
+    return parsedLabels.build();
   }
 
-  private static ImmutableList<Label> collectConstraintLabels(
-      Iterable<String> rawLabels, ImmutableMap<RepositoryName, RepositoryName> mapping)
+  private static ImmutableList<Label> parseToolchains(Sequence<?> inputs, StarlarkThread thread)
       throws EvalException {
-    ImmutableList.Builder<Label> constraintLabels = new ImmutableList.Builder<>();
-    for (String rawLabel : rawLabels) {
-      try {
-        Label constraintLabel = Label.parseAbsolute(rawLabel, mapping);
-        constraintLabels.add(constraintLabel);
-      } catch (LabelSyntaxException e) {
-        throw Starlark.errorf("Unable to parse constraint %s: %s", rawLabel, e.getMessage());
-      }
-    }
+    return parseLabels(
+        inputs.getContents(String.class, "toolchains"),
+        BazelStarlarkContext.from(thread).getRepoMapping(),
+        "toolchain");
+  }
 
-    return constraintLabels.build();
+  private static ImmutableList<Label> parseExecCompatibleWith(
+      Sequence<?> inputs, StarlarkThread thread) throws EvalException {
+    return parseLabels(
+        inputs.getContents(String.class, "exec_compatible_with"),
+        BazelStarlarkContext.from(thread).getRepoMapping(),
+        "constraint");
   }
 
   @Override
@@ -569,9 +573,7 @@
         ImmutableSet.copyOf(fragments.getContents(String.class, "fragments")),
         HostTransition.INSTANCE,
         ImmutableSet.copyOf(hostFragments.getContents(String.class, "host_fragments")),
-        collectToolchainLabels(
-            toolchains.getContents(String.class, "toolchains"),
-            BazelStarlarkContext.from(thread).getRepoMapping()),
+        parseToolchains(toolchains, thread),
         applyToGeneratingRules);
   }