Tighten the types of some of the machinery surrounding .bzl skyframe inlining

Tighten SkyKey to StarlarkImportLookupValue.Key for the internal functions of StarlarkImportLookupFunction and its inlined (non-Skyframe) caller. This avoids all but one downcast to [...].Key, in compute(), as is expected. Note the naming convention for vars -- "SkyKey skyKey", but "StarlarkImportLookupFunction.Key key".

Also eliminate a redundant case in PackageFunction#computeStarlarkImportMapWithInlining, at the expense of making the quick return path not self-evident; added a comment to compensate.

This is refactoring work toward adding a new kind of .bzl loading context, for Bazel-internal .bzl files.

Work toward #11437.

RELNOTES: None
PiperOrigin-RevId: 312840745
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 cca5d99..266be0c 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
@@ -648,8 +648,8 @@
   }
 
   /**
-   * Compute the StarlarkImportLookupValue for all given SkyKeys using vanilla skyframe evaluation,
-   * returning {@code null} if skyframe deps were missing and have been requested.
+   * Compute the StarlarkImportLookupValue for all given keys using vanilla Skyframe evaluation,
+   * returning {@code null} if Skyframe deps were missing and have been requested.
    */
   @Nullable
   private static List<StarlarkImportLookupValue> computeStarlarkImportsNoInlining(
@@ -668,9 +668,9 @@
   }
 
   /**
-   * Compute the StarlarkImportLookupValue for all given SkyKeys by "inlining" the
-   * StarlarkImportLookupFunction and bypassing traditional skyframe evaluation, returning {@code
-   * null} if skyframe deps were missing and have been requested.
+   * Compute the StarlarkImportLookupValue for all given keys by "inlining" the
+   * StarlarkImportLookupFunction and bypassing traditional Skyframe evaluation, returning {@code
+   * null} if Skyframe deps were missing and have been requested.
    */
   @Nullable
   private static List<StarlarkImportLookupValue> computeStarlarkImportsWithInlining(
@@ -682,20 +682,19 @@
         Lists.newArrayListWithExpectedSize(keys.size());
     Exception deferredException = null;
     boolean valuesMissing = false;
-    // For each listed import in order, try to compute its StarlarkImportLookupValue.
+    // Compute StarlarkImportLookupValue for each key, sharing this map as one big cache. This
+    // ensures that each .bzl is loaded only once, regardless of diamond dependencies. (Multiple
+    // loads of the same .bzl would screw up identity equality of some Starlark symbols.)
     Map<StarlarkImportLookupValue.Key, CachedStarlarkImportLookupValueAndDeps>
         visitedDepsInToplevelLoad = new HashMap<>();
     for (StarlarkImportLookupValue.Key key : keys) {
       SkyValue skyValue;
       try {
-        if (visitedDepsInToplevelLoad.containsKey(key)) {
-          skyValue = visitedDepsInToplevelLoad.get(key).getValue();
-        } else {
-          skyValue =
-              starlarkImportLookupFunctionForInlining
-                  .computeWithSelfInlineCallsForPackageAndWorkspaceNodes(
-                      key, env, visitedDepsInToplevelLoad);
-        }
+        // Will complete right away if it's already cached in visitedDepsInToplevelLoad.
+        skyValue =
+            starlarkImportLookupFunctionForInlining
+                .computeWithSelfInlineCallsForPackageAndWorkspaceNodes(
+                    key, env, visitedDepsInToplevelLoad);
       } catch (StarlarkImportFailedException | InconsistentFilesystemException e) {
         // For determinism's sake while inlining, preserve the first exception and continue to run
         // subsequently listed imports to completion/exception, loading all transitive deps anyway.
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/StarlarkImportLookupFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/StarlarkImportLookupFunction.java
index cb92629..cb27011 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/StarlarkImportLookupFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/StarlarkImportLookupFunction.java
@@ -172,7 +172,7 @@
 
   @Nullable
   StarlarkImportLookupValue computeWithSelfInlineCallsForPackageAndWorkspaceNodes(
-      SkyKey skyKey,
+      StarlarkImportLookupValue.Key key,
       Environment env,
       Map<StarlarkImportLookupValue.Key, CachedStarlarkImportLookupValueAndDeps>
           visitedDepsInToplevelLoad)
@@ -185,7 +185,7 @@
     // error.
     CachedStarlarkImportLookupValueAndDeps cachedStarlarkImportLookupValueAndDeps =
         computeWithSelfInlineCallsInternal(
-            skyKey,
+            key,
             env,
             /*visitedNested=*/ new LinkedHashSet<>(),
             /*visitedDepsInToplevelLoad=*/ visitedDepsInToplevelLoad);
@@ -197,27 +197,39 @@
 
   @Nullable
   private CachedStarlarkImportLookupValueAndDeps computeWithSelfInlineCallsInternal(
-      SkyKey skyKey,
+      StarlarkImportLookupValue.Key key,
       Environment env,
       Set<Label> visitedNested,
       Map<StarlarkImportLookupValue.Key, CachedStarlarkImportLookupValueAndDeps>
           visitedDepsInToplevelLoad)
       throws InconsistentFilesystemException, StarlarkImportFailedException, InterruptedException {
-    StarlarkImportLookupValue.Key key = (StarlarkImportLookupValue.Key) skyKey.argument();
-    Label label = key.getLabel();
-
-    // If we've visited a StarlarkImportLookupValue through some other load path for a given
-    // package, we must use the existing value to preserve reference equality between Starlark
-    //  values that ought to be the same. See b/138598337 for details.
+    // Under StarlarkImportLookupFunction inlining, BUILD and WORKSPACE files are evaluated in
+    // separate Skyframe threads, but all the .bzls transitively loaded by a single package occur in
+    // one thread. All these threads share a global cache in selfInliningManager, so that once any
+    // thread completes evaluation of a .bzl, it needn't be evaluated again (unless it's evicted).
+    //
+    // If two threads race to evaluate the same .bzl, each one will see a different copy of it, and
+    // only one will end up in the global cache. This presents a hazard if the same BUILD or
+    // WORKSPACE file has a diamond dependency on foo.bzl, evaluates it the first time, and gets a
+    // different copy of it from the cache the second time. This is because Starlark values may use
+    // object identity, which breaks the moment two distinct observable copies are visible in the
+    // same context (see b/138598337).
+    //
+    // (Note that blocking evaluation of .bzls on retrievals from the global cache doesn't work --
+    // two threads could deadlock while trying to evaluate an illegal load() cycle from opposite
+    // ends.)
+    //
+    // To solve this, we keep a second cache in visitedDepsInToplevelLoad, of just the .bzls
+    // transitively loaded in the current package. The entry for foo.bzl may be a different copy
+    // than the one in the global cache, but the BUILD or WORKSPACE file won't know the difference.
+    // (We don't need to worry about Starlark values from different packages interacting since
+    // inlining is only used for the loading phase.)
+    //
     CachedStarlarkImportLookupValueAndDeps cachedStarlarkImportLookupValueAndDeps =
         visitedDepsInToplevelLoad.get(key);
     if (cachedStarlarkImportLookupValueAndDeps == null) {
-      // Note that we can't block other threads on the computation of this value due to a potential
-      // deadlock on a cycle. Although we are repeating some work, it is possible we have an import
-      // cycle where one thread starts at one side of the cycle and the other thread starts at the
-      // other side, and they then wait forever on the results of each others computations.
       cachedStarlarkImportLookupValueAndDeps =
-          selfInliningManager.starlarkImportLookupValueCache.getIfPresent(skyKey);
+          selfInliningManager.starlarkImportLookupValueCache.getIfPresent(key);
       if (cachedStarlarkImportLookupValueAndDeps != null) {
         cachedStarlarkImportLookupValueAndDeps.traverse(
             env::registerDependencies, visitedDepsInToplevelLoad);
@@ -227,6 +239,7 @@
       return cachedStarlarkImportLookupValueAndDeps;
     }
 
+    Label label = key.getLabel();
     if (!visitedNested.add(label)) {
       ImmutableList<Label> cycle =
           CycleUtils.splitIntoPathAndChain(Predicates.equalTo(label), visitedNested).second;
@@ -263,7 +276,7 @@
       cachedStarlarkImportLookupValueAndDeps = inlineCachedValueBuilder.build();
       visitedDepsInToplevelLoad.put(key, cachedStarlarkImportLookupValueAndDeps);
       selfInliningManager.starlarkImportLookupValueCache.put(
-          skyKey, cachedStarlarkImportLookupValueAndDeps);
+          key, cachedStarlarkImportLookupValueAndDeps);
     }
     return cachedStarlarkImportLookupValueAndDeps;
   }
@@ -329,9 +342,9 @@
   // to handle though.
   @Nullable
   private StarlarkImportLookupValue computeInternal(
-      SkyKey skyKey, Environment env, @Nullable InliningState inliningState)
+      StarlarkImportLookupValue.Key key, Environment env, @Nullable InliningState inliningState)
       throws InconsistentFilesystemException, StarlarkImportFailedException, InterruptedException {
-    Label label = ((StarlarkImportLookupValue.Key) skyKey).getLabel();
+    Label label = key.getLabel();
     PathFragment filePath = label.toPathFragment();
 
     StarlarkSemantics starlarkSemantics = PrecomputedValue.STARLARK_SEMANTICS.get(env);
@@ -358,7 +371,7 @@
     try {
       result =
           computeInternalWithAst(
-              skyKey, filePath, starlarkSemantics, astLookupValue, env, inliningState);
+              key, filePath, starlarkSemantics, astLookupValue, env, inliningState);
     } catch (InconsistentFilesystemException
         | StarlarkImportFailedException
         | InterruptedException e) {
@@ -374,14 +387,13 @@
 
   @Nullable
   private StarlarkImportLookupValue computeInternalWithAst(
-      SkyKey skyKey,
+      StarlarkImportLookupValue.Key key,
       PathFragment filePath,
       StarlarkSemantics starlarkSemantics,
       ASTFileLookupValue astLookupValue,
       Environment env,
       @Nullable InliningState inliningState)
       throws InconsistentFilesystemException, StarlarkImportFailedException, InterruptedException {
-    StarlarkImportLookupValue.Key key = (StarlarkImportLookupValue.Key) skyKey;
     Label label = key.getLabel();
 
     if (!astLookupValue.lookupSuccessful()) {
@@ -458,8 +470,7 @@
   }
 
   private static ImmutableMap<RepositoryName, RepositoryName> getRepositoryMapping(
-      SkyKey skyKey, Environment env) throws InterruptedException {
-    StarlarkImportLookupValue.Key key = (StarlarkImportLookupValue.Key) skyKey;
+      StarlarkImportLookupValue.Key key, Environment env) throws InterruptedException {
     Label enclosingFileLabel = key.getLabel();
 
     ImmutableMap<RepositoryName, RepositoryName> repositoryMapping;
@@ -556,19 +567,19 @@
   }
 
   /**
-   * Compute the StarlarkImportLookupValue for all given SkyKeys using vanilla skyframe evaluation,
-   * returning {@code null} if skyframe deps were missing and have been requested.
+   * Compute the StarlarkImportLookupValue for all given keys using vanilla Skyframe evaluation,
+   * returning {@code null} if Skyframe deps were missing and have been requested.
    */
   @Nullable
   private static List<StarlarkImportLookupValue> computeStarlarkImportsNoInlining(
-      Environment env, List<? extends SkyKey> keys, Location locationForErrors)
+      Environment env, List<StarlarkImportLookupValue.Key> keys, Location locationForErrors)
       throws StarlarkImportFailedException, InterruptedException {
     List<StarlarkImportLookupValue> starlarkImports =
         Lists.newArrayListWithExpectedSize(keys.size());
     Map<SkyKey, ValueOrException<StarlarkImportFailedException>> values =
         env.getValuesOrThrow(keys, StarlarkImportFailedException.class);
     // Uses same order as load()s in the file. Order matters since we report the first error.
-    for (SkyKey key : keys) {
+    for (StarlarkImportLookupValue.Key key : keys) {
       try {
         starlarkImports.add((StarlarkImportLookupValue) values.get(key).get());
       } catch (StarlarkImportFailedException exn) {
@@ -580,13 +591,16 @@
   }
 
   /**
-   * Compute the StarlarkImportLookupValue for all given SkyKeys by reusing this instance of the
-   * StarlarkImportLookupFunction, bypassing traditional skyframe evaluation, returning {@code null}
-   * if skyframe deps were missing and have been requested.
+   * Compute the StarlarkImportLookupValue for all given keys by reusing this instance of the
+   * StarlarkImportLookupFunction, bypassing traditional Skyframe evaluation, returning {@code null}
+   * if Skyframe deps were missing and have been requested.
    */
   @Nullable
   private List<StarlarkImportLookupValue> computeStarlarkImportsWithSelfInlining(
-      Environment env, List<? extends SkyKey> keys, Label fileLabel, InliningState inliningState)
+      Environment env,
+      List<StarlarkImportLookupValue.Key> keys,
+      Label fileLabel,
+      InliningState inliningState)
       throws InterruptedException, StarlarkImportFailedException, InconsistentFilesystemException {
     Preconditions.checkState(
         env instanceof RecordingSkyFunctionEnvironment,
@@ -598,7 +612,7 @@
     Exception deferredException = null;
     boolean valuesMissing = false;
     // NOTE: Iterating over imports in the order listed in the file.
-    for (SkyKey key : keys) {
+    for (StarlarkImportLookupValue.Key key : keys) {
       CachedStarlarkImportLookupValueAndDeps cachedValue;
       try {
         cachedValue =
@@ -839,7 +853,8 @@
 
   private static class SelfInliningManager {
     private final int starlarkImportLookupValueCacheSize;
-    private Cache<SkyKey, CachedStarlarkImportLookupValueAndDeps> starlarkImportLookupValueCache;
+    private Cache<StarlarkImportLookupValue.Key, CachedStarlarkImportLookupValueAndDeps>
+        starlarkImportLookupValueCache;
     private CachedStarlarkImportLookupValueAndDepsBuilderFactory
         cachedStarlarkImportLookupValueAndDepsBuilderFactory =
             new CachedStarlarkImportLookupValueAndDepsBuilderFactory();