Automated rollback of commit 00a4fefe594069d47d1bde99b28c6b8dcca0a7c1.

*** Reason for rollback ***

b/285381501

*** Original change description ***

Use `PackageLookupValue` to do package lookup and subpackage boundary cross check in `BzlLoadFunction`.

This is a similar change as https://github.com/bazelbuild/bazel/commit/c3a838b172088e0eaa6da0745cea0e07bcf646a1 in which we switch from using `ContainingPackageLookupValue` to `PackageLookupValue` for `PackageFunction`.

PiperOrigin-RevId: 537190556
Change-Id: Id6368b98cd80575f728ee91e730a727ac164459b
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
index 1b30aa2..876d56c 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BzlLoadFunction.java
@@ -50,7 +50,6 @@
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.server.FailureDetails.StarlarkLoading;
 import com.google.devtools.build.lib.server.FailureDetails.StarlarkLoading.Code;
-import com.google.devtools.build.lib.skyframe.PackageLookupValue.NoRepositoryPackageLookupValue;
 import com.google.devtools.build.lib.skyframe.StarlarkBuiltinsFunction.BuiltinsFailedException;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.Fingerprint;
@@ -64,7 +63,6 @@
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.SkyValue;
 import com.google.devtools.build.skyframe.SkyframeLookupResult;
-import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedHashSet;
@@ -646,103 +644,45 @@
       return key.getCompileKey(getBuiltinsRoot(builtinsBzlPath));
     }
 
-    // The block below derives all (sub)directories that could possibly contain (sub)packages and
-    // add them to a list of PackageLookup keys. These (sub)directories include the label path, and
-    // all subdirectories from label path to the bzl file. For example,
-    // 1. If the label is //a/b/c:d.bzl, allPackageLookupKeys only contains //a/b/c. There is no
-    // subdirectory under label path.
-    // 2. If the label name contains '/', for example, //a/b/c:d/e/f.bzl, allPackageLookupKeys
-    // contain //a/b/c, //a/b/c/d and //a/b/c/d/e.
-    List<PackageLookupValue.Key> allPackageLookupKeys = new ArrayList<>();
-    allPackageLookupKeys.add(PackageLookupValue.key(label.getPackageIdentifier()));
-    RepositoryName labelRepository = label.getRepository();
-    PathFragment subpkgPath = label.getPackageFragment();
-    PathFragment labelAsRelativePath = PathFragment.create(label.getName()).getParentDirectory();
-    for (String segment : labelAsRelativePath.segments()) {
-      subpkgPath = subpkgPath.getRelative(segment);
-      PackageLookupValue.Key currentPackageLookupKey =
-          PackageLookupValue.key(PackageIdentifier.create(labelRepository, subpkgPath));
-      allPackageLookupKeys.add(currentPackageLookupKey);
+    // Do package lookup.
+    PathFragment dir = Label.getContainingDirectory(label);
+    PackageIdentifier dirId = PackageIdentifier.create(label.getRepository(), dir);
+    ContainingPackageLookupValue packageLookup;
+    try {
+      packageLookup =
+          (ContainingPackageLookupValue)
+              env.getValueOrThrow(
+                  ContainingPackageLookupValue.key(dirId),
+                  BuildFileNotFoundException.class,
+                  InconsistentFilesystemException.class);
+    } catch (BuildFileNotFoundException | InconsistentFilesystemException e) {
+      throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e);
+    }
+    if (packageLookup == null) {
+      return null;
     }
 
-    SkyframeLookupResult packageLookupResults = env.getValuesAndExceptions(allPackageLookupKeys);
-
-    // We intentionally choose not to check `env.valuesMissing()` here. It is possible that all
-    // PackageLookupValues are already not null but `env.valuesMissing()` is still true from a prior
-    // request. Returning `null` in this case causes unnecessary Skyframe restarts.
-
-    PackageLookupValue.Key candidateKey = null;
-    PackageLookupValue candidateValue = null;
-    for (PackageLookupValue.Key packageLookupKey : allPackageLookupKeys) {
-      // Iterate in order of the directory structure so that the candidate{Key,Value} will end up as
-      // the deepest package, in other words the "containing package".
-      PackageLookupValue packageLookupValue;
-      try {
-        packageLookupValue =
-            (PackageLookupValue)
-                packageLookupResults.getOrThrow(
-                    packageLookupKey,
-                    BuildFileNotFoundException.class,
-                    InconsistentFilesystemException.class);
-      } catch (BuildFileNotFoundException | InconsistentFilesystemException e) {
-        throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e);
-      }
-
-      if (packageLookupValue == null) {
-        return null;
-      }
-
-      if (packageLookupValue instanceof NoRepositoryPackageLookupValue) {
-        throw BzlLoadFailedException.noBuildFile(label, packageLookupValue.getErrorMsg());
-      }
-
-      if (packageLookupValue.packageExists()) {
-        candidateKey = packageLookupKey;
-        candidateValue = packageLookupValue;
-      }
-    }
-
-    if (candidateKey != null && candidateKey.argument().equals(label.getPackageIdentifier())) {
-      if (candidateValue.packageExists()) {
-        return key.getCompileKey(candidateValue.getRoot());
-      } else {
-        throw BzlLoadFailedException.noBuildFile(label, candidateValue.getErrorMsg());
-      }
+    // Resolve to compile key or error.
+    BzlCompileValue.Key compileKey;
+    boolean packageOk =
+        packageLookup.hasContainingPackage()
+            && packageLookup.getContainingPackageName().equals(label.getPackageIdentifier());
+    if (key.isBuildPrelude() && !packageOk) {
+      // Ignore the prelude, its package doesn't exist.
+      compileKey = BzlCompileValue.EMPTY_PRELUDE_KEY;
     } else {
-      if (key.isBuildPrelude()) {
-        return BzlCompileValue.EMPTY_PRELUDE_KEY;
-      }
-      if (candidateKey == null) {
-        // If we cannot find any subpackage below label's package directory, it is still possible
-        // that the label's package is a subpackage itself. This case should be rare, so we choose
-        // to still handle it using ContainingPackageLookup node.
-        ContainingPackageLookupValue containingPackageLookup;
-        try {
-          containingPackageLookup =
-              (ContainingPackageLookupValue)
-                  env.getValueOrThrow(
-                      ContainingPackageLookupValue.key(label.getPackageIdentifier()),
-                      BuildFileNotFoundException.class,
-                      InconsistentFilesystemException.class);
-        } catch (BuildFileNotFoundException | InconsistentFilesystemException e) {
-          throw BzlLoadFailedException.errorFindingContainingPackage(label.toPathFragment(), e);
-        }
-
-        if (containingPackageLookup == null) {
-          return null;
-        }
-
-        if (containingPackageLookup.hasContainingPackage()) {
-          throw BzlLoadFailedException.labelSubpackageCrossesBoundary(
-              label, containingPackageLookup);
-        } else {
-          throw BzlLoadFailedException.noBuildFile(label, /* reason= */ null);
-        }
+      if (packageOk) {
+        compileKey = key.getCompileKey(packageLookup.getContainingPackageRoot());
       } else {
-        throw BzlLoadFailedException.subpackageCrossesLabelPackageBoundary(
-            label, candidateKey.argument(), candidateValue);
+        if (!packageLookup.hasContainingPackage()) {
+          throw BzlLoadFailedException.noBuildFile(
+              label, packageLookup.getReasonForNoContainingPackage());
+        } else {
+          throw BzlLoadFailedException.labelCrossesPackageBoundary(label, packageLookup);
+        }
       }
     }
+    return compileKey;
   }
 
   private Root getBuiltinsRoot(String builtinsBzlPath) {
@@ -1643,21 +1583,17 @@
           Code.PACKAGE_NOT_FOUND);
     }
 
-    static BzlLoadFailedException labelSubpackageCrossesBoundary(
+    static BzlLoadFailedException labelCrossesPackageBoundary(
         Label label, ContainingPackageLookupValue containingPackageLookupValue) {
       return new BzlLoadFailedException(
-          ContainingPackageLookupValue.getErrorMessageForLabelSubpackageCrossesBoundary(
-              containingPackageLookupValue, label),
-          Code.LABEL_CROSSES_PACKAGE_BOUNDARY);
-    }
-
-    static BzlLoadFailedException subpackageCrossesLabelPackageBoundary(
-        Label label,
-        PackageIdentifier subpackageIdentifier,
-        PackageLookupValue packageLookupValue) {
-      return new BzlLoadFailedException(
-          PackageLookupValue.getErrorMessageForSubpackageCrossesLabelPackageBoundary(
-              packageLookupValue.getRoot(), label, subpackageIdentifier, packageLookupValue),
+          ContainingPackageLookupValue.getErrorMessageForLabelCrossingPackageBoundary(
+              // We don't actually know the proper Root to pass in here (since we don't e.g. know
+              // the root of the bzl/BUILD file that is trying to load 'label'). Therefore we just
+              // pass in the Root of the containing package in order to still get a useful error
+              // message for the user.
+              containingPackageLookupValue.getContainingPackageRoot(),
+              label,
+              containingPackageLookupValue),
           Code.LABEL_CROSSES_PACKAGE_BOUNDARY);
     }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupValue.java
index acfc817..444c15b 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ContainingPackageLookupValue.java
@@ -59,27 +59,48 @@
     return Key.create(id);
   }
 
-  /**
-   * Creates the error message for the input {@linkplain Label label} if label itself is a
-   * subpackage crosses boundary when an outer package exists.
-   */
-  static String getErrorMessageForLabelSubpackageCrossesBoundary(
-      ContainingPackageLookupValue containingPkgLookupValue, Label label) {
+  static String getErrorMessageForLabelCrossingPackageBoundary(
+      Root pkgRoot,
+      Label label,
+      ContainingPackageLookupValue containingPkgLookupValue) {
     PackageIdentifier containingPkg = containingPkgLookupValue.getContainingPackageName();
-    Preconditions.checkState(
-        label.getPackageIdentifier().getSourceRoot().startsWith(containingPkg.getSourceRoot()),
-        "Label's path should start with outer package's path.");
-
-    String message =
-        String.format(
-            "Label '%s' is invalid because '%s' is not a package", label, label.getPackageName());
-    PathFragment labelNameInContainingPackage =
-        label.toPathFragment().relativeTo(containingPkg.getPackageFragment());
-    message += "; perhaps you meant to put the colon here: '";
-    if (containingPkg.getRepository().isMain()) {
-      message += "//";
+    boolean crossesPackageBoundaryBelow =
+        containingPkg.getSourceRoot().startsWith(label.getPackageIdentifier().getSourceRoot());
+    PathFragment labelNameFragment = PathFragment.create(label.getName());
+    String message;
+    if (crossesPackageBoundaryBelow) {
+      message =
+          String.format("Label '%s' is invalid because '%s' is a subpackage", label, containingPkg);
+    } else {
+      message =
+          String.format(
+              "Label '%s' is invalid because '%s' is not a package", label, label.getPackageName());
     }
-    message += containingPkg + ":" + labelNameInContainingPackage + "'?";
+
+    Root containingRoot = containingPkgLookupValue.getContainingPackageRoot();
+    if (pkgRoot.equals(containingRoot)) {
+      PathFragment containingPkgFragment = containingPkg.getPackageFragment();
+      PathFragment labelNameInContainingPackage =
+          crossesPackageBoundaryBelow
+              ? labelNameFragment.subFragment(
+                  containingPkgFragment.segmentCount()
+                      - label.getPackageFragment().segmentCount(),
+                  labelNameFragment.segmentCount())
+              : label.toPathFragment().relativeTo(containingPkgFragment);
+      message += "; perhaps you meant to put the colon here: '";
+      if (containingPkg.getRepository().isMain()) {
+        message += "//";
+      }
+      message += containingPkg + ":" + labelNameInContainingPackage + "'?";
+    } else {
+      message +=
+          "; have you deleted "
+              + containingPkg
+              + "/BUILD? "
+              + "If so, use the --deleted_packages="
+              + containingPkg
+              + " option";
+    }
     return message;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
index 08d73e4..30d84e8 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageFunction.java
@@ -881,7 +881,7 @@
       return true;
     }
     String errMsg =
-        PackageLookupValue.getErrorMessageForSubpackageCrossesLabelPackageBoundary(
+        PackageLookupValue.getErrorMessageForLabelCrossingPackageBoundary(
             pkgRoot, target.getLabel(), subpackageIdentifier, packageLookupValue);
     if (errMsg != null) {
       Event error =
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupValue.java b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupValue.java
index 710c8cf..e95c046 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupValue.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PackageLookupValue.java
@@ -401,13 +401,13 @@
   }
 
   /**
-   * Creates the error message for the input {@linkplain Label label} if it contains a subpackage
-   * crossing boundary.
+   * Creates the error message for the input {@linkplain Label label} has a subpackage crossing
+   * boundary.
    *
    * <p>Returns {@code null} if no subpackage is discovered or the subpackage is marked as DELETED.
    */
   @Nullable
-  static String getErrorMessageForSubpackageCrossesLabelPackageBoundary(
+  static String getErrorMessageForLabelCrossingPackageBoundary(
       Root pkgRoot,
       Label label,
       PackageIdentifier subpackageIdentifier,
@@ -422,19 +422,19 @@
       if (pkgRoot.equals(subPackageRoot)) {
         PathFragment labelRootPathFragment = label.getPackageIdentifier().getSourceRoot();
         PathFragment subpackagePathFragment = subpackageIdentifier.getSourceRoot();
-        Preconditions.checkState(
-            subpackagePathFragment.startsWith(labelRootPathFragment),
-            "Subpackage should start with label's package path when they share the same package"
-                + " root");
-        PathFragment labelNameInSubpackage =
-            PathFragment.create(label.getName())
-                .subFragment(
-                    subpackagePathFragment.segmentCount() - labelRootPathFragment.segmentCount());
-        message += "; perhaps you meant to put the" + " colon here: '";
-        if (subpackageIdentifier.getRepository().isMain()) {
-          message += "//";
+        if (subpackagePathFragment.startsWith(labelRootPathFragment)) {
+          PathFragment labelNameInSubpackage =
+              PathFragment.create(label.getName())
+                  .subFragment(
+                      subpackagePathFragment.segmentCount() - labelRootPathFragment.segmentCount());
+          message += "; perhaps you meant to put the" + " colon here: '";
+          if (subpackageIdentifier.getRepository().isMain()) {
+            message += "//";
+          }
+          message += subpackageIdentifier + ":" + labelNameInSubpackage + "'?";
+        } else {
+          // TODO: Is this a valid case? How do we handle this case?
         }
-        message += subpackageIdentifier + ":" + labelNameInSubpackage + "'?";
       } else {
         message +=
             "; have you deleted "
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
index 76521d1..ffdf08d 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/PackageFunctionTest.java
@@ -1679,7 +1679,9 @@
 
     @Test
     public void testPreludeNeedNotBePresent() throws Exception {
-      scratch.file("pkg/BUILD", "print('FOO')");
+      scratch.file(
+          "pkg/BUILD", //
+          "print('FOO')");
 
       getConfiguredTarget("//pkg:BUILD");
       assertContainsEvent("FOO");