Use toolchain resolution in rule creation.

Part of #2219.

Change-Id: Id4929d5ddcd57b4635af5e513eb9a09f16a78e71
PiperOrigin-RevId: 162634398
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 27cc526..0d11365 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -42,6 +42,7 @@
 import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
 import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.ToolchainContext;
 import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -72,6 +73,8 @@
 import com.google.devtools.build.lib.skyframe.AspectFunction.AspectCreationException;
 import com.google.devtools.build.lib.skyframe.AspectValue.AspectKey;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor.BuildViewProvider;
+import com.google.devtools.build.lib.skyframe.ToolchainUtil.ToolchainContextException;
+import com.google.devtools.build.lib.skyframe.ToolchainUtil.UnresolvedToolchainsException;
 import com.google.devtools.build.lib.syntax.EvalException;
 import com.google.devtools.build.lib.util.OrderedSetMultimap;
 import com.google.devtools.build.lib.util.Preconditions;
@@ -99,12 +102,12 @@
 /**
  * SkyFunction for {@link ConfiguredTargetValue}s.
  *
- * This class, together with {@link AspectFunction} drives the analysis phase. For more information,
- * see {@link com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory}.
+ * <p>This class, together with {@link AspectFunction} drives the analysis phase. For more
+ * information, see {@link com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory}.
  *
  * @see com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory
  */
-final class ConfiguredTargetFunction implements SkyFunction {
+public final class ConfiguredTargetFunction implements SkyFunction {
   // This construction is a bit funky, but guarantees that the Object reference here is globally
   // unique.
   static final ImmutableMap<Label, ConfigMatchingProvider> NO_CONFIG_CONDITIONS =
@@ -231,6 +234,19 @@
             new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
       }
 
+      // Determine what toolchains are needed by this target.
+      ToolchainContext toolchainContext = null;
+      if (target instanceof Rule) {
+        ImmutableList<Label> requiredToolchains =
+            ((Rule) target).getRuleClassObject().getRequiredToolchains();
+        toolchainContext =
+            ToolchainUtil.createToolchainContext(env, requiredToolchains, configuration);
+        if (env.valuesMissing()) {
+          return null;
+        }
+      }
+
+      // Calculate the dependencies of this target.
       OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap =
           computeDependencies(
               env,
@@ -238,6 +254,7 @@
               ctgValue,
               ImmutableList.<Aspect>of(),
               configConditions,
+              toolchainContext,
               ruleClassProvider,
               view.getHostConfiguration(configuration),
               transitivePackages,
@@ -250,8 +267,16 @@
             new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
       }
       Preconditions.checkNotNull(depValueMap);
-      ConfiguredTargetValue ans = createConfiguredTarget(
-          view, env, target, configuration, depValueMap, configConditions, transitivePackages);
+      ConfiguredTargetValue ans =
+          createConfiguredTarget(
+              view,
+              env,
+              target,
+              configuration,
+              depValueMap,
+              configConditions,
+              toolchainContext,
+              transitivePackages);
       return ans;
     } catch (DependencyEvaluationException e) {
       if (e.getCause() instanceof ConfiguredValueCreationException) {
@@ -276,28 +301,45 @@
       }
       throw new ConfiguredTargetFunctionException(
           new ConfiguredValueCreationException(e.getMessage(), analysisRootCause));
+    } catch (ToolchainContextException e) {
+      if (e.getCause() instanceof UnresolvedToolchainsException) {
+        UnresolvedToolchainsException ute = (UnresolvedToolchainsException) e.getCause();
+        env.getListener()
+            .handle(Event.error(ute.getMessage() + " for target " + target.getLabel()));
+        throw new ConfiguredTargetFunctionException(
+            new ConfiguredValueCreationException(ute.getMessage(), target.getLabel()));
+      } else if (e.getCause() instanceof ConfiguredValueCreationException) {
+        ConfiguredValueCreationException cvce = (ConfiguredValueCreationException) e.getCause();
+        throw new ConfiguredTargetFunctionException(cvce);
+      } else {
+        // TODO(katre): better error handling
+        throw new ConfiguredTargetFunctionException(
+            new ConfiguredValueCreationException(e.getMessage()));
+      }
     } finally {
       cpuBoundSemaphore.release();
     }
   }
 
   /**
-   * Computes the direct dependencies of a node in the configured target graph (a configured
-   * target or an aspects).
+   * Computes the direct dependencies of a node in the configured target graph (a configured target
+   * or an aspects).
    *
    * <p>Returns null if Skyframe hasn't evaluated the required dependencies yet. In this case, the
    * caller should also return null to Skyframe.
-   *  @param env the Skyframe environment
+   *
+   * @param env the Skyframe environment
    * @param resolver the dependency resolver
    * @param ctgValue the label and the configuration of the node
    * @param aspects
    * @param configConditions the configuration conditions for evaluating the attributes of the node
+   * @param toolchainContext context information for required toolchains
    * @param ruleClassProvider rule class provider for determining the right configuration fragments
-   *   to apply to deps
+   *     to apply to deps
    * @param hostConfiguration the host configuration. There's a noticeable performance hit from
    *     instantiating this on demand for every dependency that wants it, so it's best to compute
    *     the host configuration as early as possible and pass this reference to all consumers
-   * */
+   */
   @Nullable
   static OrderedSetMultimap<Attribute, ConfiguredTarget> computeDependencies(
       Environment env,
@@ -305,17 +347,24 @@
       TargetAndConfiguration ctgValue,
       Iterable<Aspect> aspects,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+      @Nullable ToolchainContext toolchainContext,
       RuleClassProvider ruleClassProvider,
       BuildConfiguration hostConfiguration,
       NestedSetBuilder<Package> transitivePackages,
       NestedSetBuilder<Label> transitiveLoadingRootCauses)
       throws DependencyEvaluationException, ConfiguredTargetFunctionException,
-      AspectCreationException, InterruptedException {
+          AspectCreationException, InterruptedException {
     // Create the map from attributes to set of (target, configuration) pairs.
     OrderedSetMultimap<Attribute, Dependency> depValueNames;
     try {
-      depValueNames = resolver.dependentNodeMap(
-          ctgValue, hostConfiguration, aspects, configConditions, transitiveLoadingRootCauses);
+      depValueNames =
+          resolver.dependentNodeMap(
+              ctgValue,
+              hostConfiguration,
+              aspects,
+              configConditions,
+              toolchainContext,
+              transitiveLoadingRootCauses);
     } catch (EvalException e) {
       // EvalException can only be thrown by computed Skylark attributes in the current rule.
       env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
@@ -1102,10 +1151,14 @@
   }
 
   @Nullable
-  private ConfiguredTargetValue createConfiguredTarget(SkyframeBuildView view,
-      Environment env, Target target, BuildConfiguration configuration,
+  private ConfiguredTargetValue createConfiguredTarget(
+      SkyframeBuildView view,
+      Environment env,
+      Target target,
+      BuildConfiguration configuration,
       OrderedSetMultimap<Attribute, ConfiguredTarget> depValueMap,
       ImmutableMap<Label, ConfigMatchingProvider> configConditions,
+      @Nullable ToolchainContext toolchainContext,
       NestedSetBuilder<Package> transitivePackages)
       throws ConfiguredTargetFunctionException, InterruptedException {
     StoredEventHandler events = new StoredEventHandler();
@@ -1122,8 +1175,14 @@
     }
 
     Preconditions.checkNotNull(depValueMap);
-    ConfiguredTarget configuredTarget = view.createConfiguredTarget(target, configuration,
-        analysisEnvironment, depValueMap, configConditions);
+    ConfiguredTarget configuredTarget =
+        view.createConfiguredTarget(
+            target,
+            configuration,
+            analysisEnvironment,
+            depValueMap,
+            configConditions,
+            toolchainContext);
 
     events.replayOn(env.getListener());
     if (events.hasErrors()) {