Refactor DependencyResolver to collect and return loading errors.

This should never be triggered in production, where we always run a loading
phase first and only analyze targets that load successfully. I.e., this is
just plumbing which will be hooked up in a subsequent change.

--
MOS_MIGRATED_REVID=113258593
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 2d0549b..4917d28 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
@@ -26,7 +26,9 @@
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.StoredEventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
@@ -105,6 +107,7 @@
       throws AspectFunctionException, InterruptedException {
     SkyframeBuildView view = buildViewProvider.getSkyframeBuildView();
     NestedSetBuilder<Package> transitivePackages = NestedSetBuilder.stableOrder();
+    NestedSetBuilder<Label> transitiveRootCauses = NestedSetBuilder.stableOrder();
     AspectKey key = (AspectKey) skyKey.argument();
     ConfiguredAspectFactory aspectFactory;
     if (key.getAspectClass() instanceof NativeAspectClass<?>) {
@@ -152,9 +155,15 @@
           "aspects must be attached to rules"));
     }
 
-    final ConfiguredTargetValue configuredTargetValue =
-        (ConfiguredTargetValue)
-            env.getValue(ConfiguredTargetValue.key(key.getLabel(), key.getConfiguration()));
+    final ConfiguredTargetValue configuredTargetValue;
+    try {
+      configuredTargetValue =
+          (ConfiguredTargetValue) env.getValueOrThrow(
+              ConfiguredTargetValue.key(key.getLabel(), key.getConfiguration()),
+              ConfiguredValueCreationException.class);
+    } catch (ConfiguredValueCreationException e) {
+      throw new AspectFunctionException(new AspectCreationException(e.getRootCauses()));
+    }
     if (configuredTargetValue == null) {
       // TODO(bazel-team): remove this check when top-level targets also use dynamic configurations.
       // Right now the key configuration may be dynamic while the original target's configuration
@@ -175,7 +184,7 @@
     try {
       // Get the configuration targets that trigger this rule's configurable attributes.
       Set<ConfigMatchingProvider> configConditions = ConfiguredTargetFunction.getConfigConditions(
-          target, env, resolver, ctgValue, transitivePackages);
+          target, env, resolver, ctgValue, transitivePackages, transitiveRootCauses);
       if (configConditions == null) {
         // Those targets haven't yet been resolved.
         return null;
@@ -190,7 +199,15 @@
               configConditions,
               ruleClassProvider,
               view.getHostConfiguration(ctgValue.getConfiguration()),
-              transitivePackages);
+              transitivePackages,
+              transitiveRootCauses);
+      if (depValueMap == null) {
+        return null;
+      }
+      if (!transitiveRootCauses.isEmpty()) {
+        throw new AspectFunctionException(
+            new AspectCreationException("Loading failed", transitiveRootCauses.build()));
+      }
 
       return createAspect(
           env,
@@ -282,6 +299,9 @@
    * An exception indicating that there was a problem creating an aspect.
    */
   public static final class AspectCreationException extends Exception {
+    /** Targets in the transitive closure that failed to load. May be empty. */
+    private final NestedSet<Label> loadingRootCauses;
+
     /**
      * The target for which analysis failed, if any. We can't represent aspects with labels, so if
      * the aspect analysis fails, this will be {@code null}.
@@ -290,11 +310,26 @@
 
     public AspectCreationException(String message, Label analysisRootCause) {
       super(message);
+      this.loadingRootCauses = NestedSetBuilder.<Label>emptySet(Order.STABLE_ORDER);
       this.analysisRootCause = analysisRootCause;
     }
 
+    public AspectCreationException(String message, NestedSet<Label> loadingRootCauses) {
+      super(message);
+      this.loadingRootCauses = loadingRootCauses;
+      this.analysisRootCause = null;
+    }
+
+    public AspectCreationException(NestedSet<Label> loadingRootCauses) {
+      this("Loading failed", loadingRootCauses);
+    }
+
     public AspectCreationException(String message) {
-      this(message, null);
+      this(message, (Label) null);
+    }
+
+    public NestedSet<Label> getRootCauses() {
+      return loadingRootCauses;
     }
 
     @Nullable public Label getAnalysisRootCause() {