Update AspectFunction to perform toolchain resolution for multiple exec groups.

RELNOTES: Aspects can now define and use exec groups using the same API as rules.
PiperOrigin-RevId: 453177050
Change-Id: Ia84ff906ede72cadfb6b6acf9deac7c55280bbe5
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 326b851..bba79c9 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -17,6 +17,7 @@
 import static com.google.common.collect.ImmutableList.toImmutableList;
 
 import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Lists;
@@ -35,6 +36,7 @@
 import com.google.devtools.build.lib.analysis.DependencyKey;
 import com.google.devtools.build.lib.analysis.DependencyKind;
 import com.google.devtools.build.lib.analysis.DuplicateException;
+import com.google.devtools.build.lib.analysis.ExecGroupCollection;
 import com.google.devtools.build.lib.analysis.ExecGroupCollection.InvalidExecGroupException;
 import com.google.devtools.build.lib.analysis.InconsistentAspectOrderException;
 import com.google.devtools.build.lib.analysis.ResolvedToolchainContext;
@@ -78,6 +80,7 @@
 import com.google.devtools.build.lib.skyframe.AspectKeyCreator.AspectKey;
 import com.google.devtools.build.lib.skyframe.BzlLoadFunction.BzlLoadFailedException;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.ComputeDependenciesState;
+import com.google.devtools.build.lib.skyframe.ConfiguredTargetFunction.ComputedToolchainContexts;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
 import com.google.devtools.build.lib.util.OrderedSetMultimap;
 import com.google.devtools.build.skyframe.SkyFunction;
@@ -88,7 +91,9 @@
 import com.google.devtools.build.skyframe.SkyframeLookupResult;
 import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import javax.annotation.Nullable;
 import net.starlark.java.eval.StarlarkSemantics;
 
@@ -271,19 +276,28 @@
     TargetAndConfiguration originalTargetAndConfiguration =
         new TargetAndConfiguration(target, configuration);
     try {
-      UnloadedToolchainContext unloadedToolchainContext =
-          getUnloadedToolchainContext(env, key, aspect, configuration);
+      ConfiguredTargetFunction.ComputedToolchainContexts computedToolchainContexts =
+          getUnloadedToolchainContexts(env, key, aspect, configuration);
       if (env.valuesMissing()) {
         return null;
       }
 
+      ToolchainCollection<UnloadedToolchainContext> unloadedToolchainContexts = null;
+      ExecGroupCollection.Builder execGroupCollectionBuilder = null;
+      if (computedToolchainContexts != null) {
+        unloadedToolchainContexts = computedToolchainContexts.toolchainCollection;
+        execGroupCollectionBuilder = computedToolchainContexts.execGroupCollectionBuilder;
+      }
+
       // Get the configuration targets that trigger this rule's configurable attributes.
       ConfigConditions configConditions =
           ConfiguredTargetFunction.getConfigConditions(
               env,
               originalTargetAndConfiguration,
               state.transitivePackagesForPackageRootResolution,
-              unloadedToolchainContext == null ? null : unloadedToolchainContext.targetPlatform(),
+              unloadedToolchainContexts == null
+                  ? null
+                  : unloadedToolchainContexts.getTargetPlatform(),
               state.transitiveRootCauses);
       if (configConditions == null) {
         // Those targets haven't yet been resolved.
@@ -302,11 +316,9 @@
                 originalTargetAndConfiguration,
                 topologicalAspectPath,
                 configConditions.asProviders(),
-                unloadedToolchainContext == null
+                unloadedToolchainContexts == null
                     ? null
-                    : ToolchainCollection.builder()
-                        .addDefaultContext(unloadedToolchainContext)
-                        .build(),
+                    : unloadedToolchainContexts.asToolchainContexts(),
                 ruleClassProvider,
                 buildViewProvider.getSkyframeBuildView().getHostConfiguration());
       } catch (ConfiguredValueCreationException e) {
@@ -326,17 +338,23 @@
       }
 
       // Load the requested toolchains into the ToolchainContext, now that we have dependencies.
-      ResolvedToolchainContext toolchainContext = null;
-      if (unloadedToolchainContext != null) {
+      ToolchainCollection<ResolvedToolchainContext> toolchainContexts = null;
+      if (unloadedToolchainContexts != null) {
         String targetDescription =
             String.format(
                 "aspect %s applied to %s", aspect.getDescriptor().getDescription(), target);
-        toolchainContext =
-            ResolvedToolchainContext.load(
-                unloadedToolchainContext,
-                targetDescription,
-                // TODO(161222568): Support exec groups on aspects.
-                depValueMap.get(DependencyKind.defaultExecGroupToolchain()));
+        ToolchainCollection.Builder<ResolvedToolchainContext> contextsBuilder =
+            ToolchainCollection.builder();
+        for (Map.Entry<String, UnloadedToolchainContext> unloadedContext :
+            unloadedToolchainContexts.getContextMap().entrySet()) {
+          Set<ConfiguredTargetAndData> toolchainDependencies =
+              depValueMap.get(DependencyKind.forExecGroup(unloadedContext.getKey()));
+          contextsBuilder.addContext(
+              unloadedContext.getKey(),
+              ResolvedToolchainContext.load(
+                  unloadedContext.getValue(), targetDescription, toolchainDependencies));
+        }
+        toolchainContexts = contextsBuilder.build();
       }
 
       return createAspect(
@@ -349,7 +367,8 @@
               associatedTarget, target, configuration, /*transitionKeys=*/ null),
           configuration,
           configConditions,
-          toolchainContext,
+          toolchainContexts,
+          execGroupCollectionBuilder,
           depValueMap,
           state.transitivePackagesForPackageRootResolution);
     } catch (DependencyEvaluationException e) {
@@ -537,36 +556,34 @@
   }
 
   @Nullable
-  private static UnloadedToolchainContext getUnloadedToolchainContext(
+  private static ComputedToolchainContexts getUnloadedToolchainContexts(
       Environment env,
       AspectKey key,
       Aspect aspect,
       @Nullable BuildConfigurationValue configuration)
       throws InterruptedException, AspectCreationException {
-    // Determine what toolchains are needed by this target.
-    UnloadedToolchainContext unloadedToolchainContext = null;
-    if (configuration != null) {
+    if (configuration == null) {
       // Configuration can be null in the case of aspects applied to input files. In this case,
       // there are no chances of toolchains being used, so skip it.
-      try {
-        unloadedToolchainContext =
-            (UnloadedToolchainContext)
-                env.getValueOrThrow(
-                    ToolchainContextKey.key()
-                        .configurationKey(configuration.getKey())
-                        .toolchainTypes(aspect.getDefinition().getToolchainTypes())
-                        .build(),
-                    ToolchainException.class);
-      } catch (ToolchainException e) {
-        // TODO(katre): better error handling
-        throw new AspectCreationException(
-            e.getMessage(), new LabelCause(key.getLabel(), e.getDetailedExitCode()));
-      }
-    }
-    if (env.valuesMissing()) {
       return null;
     }
-    return unloadedToolchainContext;
+    // Determine what toolchains are needed by this target.
+    try {
+      return ConfiguredTargetFunction.computeUnloadedToolchainContexts(
+          env,
+          key.getLabel(),
+          true,
+          Predicates.alwaysFalse(),
+          configuration.getKey(),
+          aspect.getDefinition().getToolchainTypes(),
+          aspect.getDefinition().execCompatibleWith(),
+          aspect.getDefinition().execGroups(),
+          null);
+    } catch (ToolchainException e) {
+      // TODO(katre): better error handling
+      throw new AspectCreationException(
+          e.getMessage(), new LabelCause(key.getLabel(), e.getDetailedExitCode()));
+    }
   }
 
   /**
@@ -613,12 +630,15 @@
     // Compute the Dependency from originalTarget to aliasedLabel
     Dependency dep;
     try {
-      UnloadedToolchainContext unloadedToolchainContext =
-          getUnloadedToolchainContext(env, originalKey, aspect, originalTarget.getConfiguration());
+      ConfiguredTargetFunction.ComputedToolchainContexts computedToolchainContexts =
+          getUnloadedToolchainContexts(env, originalKey, aspect, originalTarget.getConfiguration());
       if (env.valuesMissing()) {
         return null;
       }
 
+      ToolchainCollection<UnloadedToolchainContext> unloadedToolchainContexts =
+          computedToolchainContexts.toolchainCollection;
+
       // See comment in compute() above for why we pair target with aspectConfiguration here
       TargetAndConfiguration originalTargetAndAspectConfiguration =
           new TargetAndConfiguration(originalTarget.getTarget(), aspectConfiguration);
@@ -629,7 +649,9 @@
               env,
               originalTargetAndAspectConfiguration,
               transitivePackagesForPackageRootResolution,
-              unloadedToolchainContext == null ? null : unloadedToolchainContext.targetPlatform(),
+              unloadedToolchainContexts == null
+                  ? null
+                  : unloadedToolchainContexts.getTargetPlatform(),
               transitiveRootCauses);
       if (configConditions == null) {
         // Those targets haven't yet been resolved.
@@ -800,7 +822,8 @@
       ConfiguredTargetAndData associatedTarget,
       BuildConfigurationValue configuration,
       ConfigConditions configConditions,
-      ResolvedToolchainContext toolchainContext,
+      @Nullable ToolchainCollection<ResolvedToolchainContext> toolchainContexts,
+      @Nullable ExecGroupCollection.Builder execGroupCollectionBuilder,
       OrderedSetMultimap<DependencyKind, ConfiguredTargetAndData> directDeps,
       @Nullable NestedSetBuilder<Package> transitivePackagesForPackageRootResolution)
       throws AspectFunctionException, InterruptedException {
@@ -842,7 +865,8 @@
                     aspect,
                     directDeps,
                     configConditions,
-                    toolchainContext,
+                    toolchainContexts,
+                    execGroupCollectionBuilder,
                     configuration,
                     view.getHostConfiguration(),
                     key);