Make sure that absolute packages don't go through repo mapping

https://github.com/bazelbuild/bazel/commit/103ea9d3f3a0d85a0d7c1ad98fd8dbb422505d95 refactored label parsing,
getting rid of the "default" repo name (using "main" instead). This meant that absolute packages such as
"//visibility" would now always map to the main repo. This is normally correct, except that this main repo would
then go through repo mapping, so if any non-main repo tried to use such labels, they would get a "non-visible"
error (with Bzlmod enabled only; otherwise, repo mappings allow fallback). This commit fixes it so that such
usages of the main repo don't go through repo mapping at all.

Fixes https://github.com/bazelbuild/bazel/issues/14403.

Closes #14412.

PiperOrigin-RevId: 416252184
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
index d592862..fcc08a1 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/Label.java
@@ -18,6 +18,7 @@
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ComparisonChain;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Interner;
 import com.google.devtools.build.docgen.annot.DocCategory;
 import com.google.devtools.build.lib.actions.CommandLineItem;
@@ -53,6 +54,18 @@
 @Immutable
 @ThreadSafe
 public final class Label implements Comparable<Label>, StarlarkValue, SkyKey, CommandLineItem {
+  /**
+   * Package names that aren't made relative to the current repository because they mean special
+   * things to Bazel.
+   */
+  private static final ImmutableSet<String> ABSOLUTE_PACKAGE_NAMES =
+      ImmutableSet.of(
+          // Used for select's `//conditions:default` label (not a target)
+          "conditions",
+          // Used for the public and private visibility labels (not targets)
+          "visibility",
+          // There is only one //external package
+          LabelConstants.EXTERNAL_PACKAGE_NAME.getPathString());
 
   // Intern "__pkg__" and "__subpackages__" pseudo-targets, which appears in labels used for
   // visibility specifications. This saves a couple tenths of a percent of RAM off the loading
@@ -83,6 +96,18 @@
         PackageIdentifier.create(repoName, PathFragment.create(parts.pkg)), parts.target);
   }
 
+  /** Computes the repo name for the label, within the context of a current repo. */
+  private static RepositoryName computeRepoNameWithRepoContext(
+      Parts parts, RepositoryName currentRepo, RepositoryMapping repoMapping) {
+    if (parts.repo == null) {
+      // Certain package names when used without a "@" part are always absolutely in the main repo,
+      // disregarding the current repo and repo mappings.
+      return ABSOLUTE_PACKAGE_NAMES.contains(parts.pkg) ? RepositoryName.MAIN : currentRepo;
+    }
+    // TODO(b/200024947): Make repo mapping take a string and return a RepositoryName.
+    return repoMapping.get(RepositoryName.createFromValidStrippedName(parts.repo));
+  }
+
   // TODO(b/200024947): Make this public.
   /**
    * Parses a raw label string within the context of a current repo. It must be of the form {@code
@@ -94,11 +119,7 @@
       throws LabelSyntaxException {
     Parts parts = Parts.parse(raw);
     parts.checkPkgIsAbsolute();
-    // TODO(b/200024947): Make repo mapping take a string and return a RepositoryName.
-    RepositoryName repoName =
-        parts.repo == null
-            ? currentRepo
-            : repoMapping.get(RepositoryName.createFromValidStrippedName(parts.repo));
+    RepositoryName repoName = computeRepoNameWithRepoContext(parts, currentRepo, repoMapping);
     return createUnvalidated(
         PackageIdentifier.create(repoName, PathFragment.create(parts.pkg)), parts.target);
   }
@@ -119,11 +140,8 @@
     if (!parts.pkg.isEmpty()) {
       parts.checkPkgIsAbsolute();
     }
-    // TODO(b/200024947): Make repo mapping take a string and return a RepositoryName.
     RepositoryName repoName =
-        parts.repo == null
-            ? packageIdentifier.getRepository()
-            : repoMapping.get(RepositoryName.createFromValidStrippedName(parts.repo));
+        computeRepoNameWithRepoContext(parts, packageIdentifier.getRepository(), repoMapping);
     PathFragment pkgFragment =
         parts.pkgIsAbsolute
             ? PathFragment.create(parts.pkg)
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/LabelParser.java b/src/main/java/com/google/devtools/build/lib/cmdline/LabelParser.java
index 00612b9..75afd2f 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/LabelParser.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/LabelParser.java
@@ -14,26 +14,12 @@
 
 package com.google.devtools.build.lib.cmdline;
 
-import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.util.StringUtilities;
 import com.google.errorprone.annotations.FormatMethod;
 import javax.annotation.Nullable;
 
 /** Utilities to help parse labels. */
 final class LabelParser {
-  /**
-   * Package names that aren't made relative to the current repository because they mean special
-   * things to Bazel.
-   */
-  private static final ImmutableSet<String> ABSOLUTE_PACKAGE_NAMES =
-      ImmutableSet.of(
-          // Used for select's `//conditions:default` label (not a target)
-          "conditions",
-          // Used for the public and private visibility labels (not targets)
-          "visibility",
-          // There is only one //external package
-          LabelConstants.EXTERNAL_PACKAGE_NAME.getPathString());
-
   private LabelParser() {}
 
   /**
@@ -67,12 +53,9 @@
     private static Parts validateAndCreate(
         @Nullable String repo, boolean pkgIsAbsolute, String pkg, String target, String raw)
         throws LabelSyntaxException {
-      return new Parts(
-          validateAndProcessRepoName(repo, pkg),
-          pkgIsAbsolute,
-          validateAndProcessPackageName(pkg, target),
-          validateAndProcessTargetName(pkg, target),
-          raw);
+      validateRepoName(repo);
+      validatePackageName(pkg, target);
+      return new Parts(repo, pkgIsAbsolute, pkg, validateAndProcessTargetName(pkg, target), raw);
     }
 
     /**
@@ -135,30 +118,22 @@
     }
 
     @Nullable
-    private static String validateAndProcessRepoName(@Nullable String repo, String pkg)
-        throws LabelSyntaxException {
-      if (repo == null && ABSOLUTE_PACKAGE_NAMES.contains(pkg)) {
-        // These package names when used without a "@" part are always absolutely in the main repo.
-        return "";
-      }
+    private static void validateRepoName(@Nullable String repo) throws LabelSyntaxException {
       if (repo == null) {
-        return null;
+        return;
       }
       String error = RepositoryName.validate('@' + repo);
       if (error != null) {
         throw syntaxErrorf("invalid repository name '@%s': %s", repo, error);
       }
-      return repo;
     }
 
-    private static String validateAndProcessPackageName(String pkg, String target)
-        throws LabelSyntaxException {
+    private static void validatePackageName(String pkg, String target) throws LabelSyntaxException {
       String pkgError = LabelValidator.validatePackageName(pkg);
       if (pkgError != null) {
         throw syntaxErrorf(
             "invalid package name '%s': %s%s", pkg, pkgError, perhapsYouMeantMessage(pkg, target));
       }
-      return pkg;
     }
 
     void checkPkgIsAbsolute() throws LabelSyntaxException {
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/LabelTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/LabelTest.java
index 1fe0dc0..f4b89c3 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/LabelTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/LabelTest.java
@@ -198,7 +198,9 @@
     PackageIdentifier packageId = PackageIdentifier.create("@repo", PathFragment.create("foo"));
     Label base = Label.create(packageId, "bar");
 
-    Label relative = base.getRelativeWithRemapping("//conditions:default", ImmutableMap.of());
+    Label relative =
+        base.getRelativeWithRemapping(
+            "//conditions:default", RepositoryMapping.create(ImmutableMap.of(), "repo"));
 
     PackageIdentifier expected = PackageIdentifier.createInMainRepo("conditions");
     assertThat(relative.getRepository()).isEqualTo(expected.getRepository());