Automated rollback of commit 943c83aa58731c4f9561d79c458f254427a8f24c.

*** Reason for rollback ***

This CL causes memory regression for single top-level aspect described in
b/193314770

*** Original change description ***

Command line aspect-on-aspect

This CL supports aspect-on-aspect for command line aspects. Command line aspects specified via `--aspects` option will support a top-level aspect requiring aspect providers via `required_aspect_providers` to get their values from other top-level aspects advertising it that come before it in the `--aspects` list.

PiperOrigin-RevId: 384430487
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisFailureEvent.java b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisFailureEvent.java
index 2a8445a..1e8a0ef 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/AnalysisFailureEvent.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/AnalysisFailureEvent.java
@@ -30,7 +30,7 @@
 import com.google.devtools.build.lib.causes.Cause;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
+import com.google.devtools.build.lib.skyframe.AspectValueKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import java.util.Collection;
 import javax.annotation.Nullable;
@@ -40,7 +40,7 @@
  * target cannot be completed because of an error in one of its dependencies.
  */
 public class AnalysisFailureEvent implements BuildEvent {
-  @Nullable private final AspectKey failedAspect;
+  @Nullable private final AspectValueKey failedAspect;
   private final ConfiguredTargetKey failedTarget;
   private final BuildEventId configuration;
   private final NestedSet<Cause> rootCauses;
@@ -48,12 +48,12 @@
   public AnalysisFailureEvent(
       ActionLookupKey failedTarget, BuildEventId configuration, NestedSet<Cause> rootCauses) {
     Preconditions.checkArgument(
-        failedTarget instanceof ConfiguredTargetKey || failedTarget instanceof AspectKey);
+        failedTarget instanceof ConfiguredTargetKey || failedTarget instanceof AspectValueKey);
     if (failedTarget instanceof ConfiguredTargetKey) {
       this.failedAspect = null;
       this.failedTarget = (ConfiguredTargetKey) failedTarget;
     } else {
-      this.failedAspect = (AspectKey) failedTarget;
+      this.failedAspect = (AspectValueKey) failedTarget;
       this.failedTarget = failedAspect.getBaseConfiguredTargetKey();
     }
     if (configuration != null) {
@@ -65,7 +65,7 @@
   }
 
   public AnalysisFailureEvent(
-      AspectKey failedAspect, BuildEventId configuration, NestedSet<Cause> rootCauses) {
+      AspectValueKey failedAspect, BuildEventId configuration, NestedSet<Cause> rootCauses) {
     this.failedAspect = failedAspect;
     this.failedTarget = failedAspect.getBaseConfiguredTargetKey();
     if (configuration != null) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
index f835927..bec43a1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/BuildView.java
@@ -55,12 +55,13 @@
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.packages.AspectClass;
+import com.google.devtools.build.lib.packages.AspectDescriptor;
+import com.google.devtools.build.lib.packages.AspectParameters;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.NativeAspectClass;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.Rule;
-import com.google.devtools.build.lib.packages.StarlarkAspectClass;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TargetUtils;
 import com.google.devtools.build.lib.pkgcache.PackageManager;
@@ -74,7 +75,6 @@
 import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns.Code;
 import com.google.devtools.build.lib.skyframe.AspectValueKey;
 import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.TopLevelAspectsKey;
 import com.google.devtools.build.lib.skyframe.BuildConfigurationValue;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.skyframe.CoverageReportValue;
@@ -86,6 +86,7 @@
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.util.RegexFilter;
 import com.google.devtools.build.skyframe.WalkableGraph;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -274,7 +275,10 @@
             .map(TargetAndConfiguration::getConfiguredTargetKey)
             .collect(Collectors.toList());
 
-    ImmutableList.Builder<AspectClass> aspectClassesBuilder = ImmutableList.builder();
+    Multimap<Pair<Label, String>, BuildConfiguration> aspectConfigurations =
+        ArrayListMultimap.create();
+
+    List<AspectValueKey> aspectKeys = new ArrayList<>();
     for (String aspect : aspects) {
       // Syntax: label%aspect
       int delimiterPosition = aspect.indexOf('%');
@@ -314,14 +318,38 @@
               createFailureDetail(errorMessage, Analysis.Code.ASPECT_LABEL_SYNTAX_ERROR),
               e);
         }
+
         String starlarkFunctionName = aspect.substring(delimiterPosition + 1);
-        aspectClassesBuilder.add(new StarlarkAspectClass(starlarkFileLabel, starlarkFunctionName));
+        for (TargetAndConfiguration targetSpec : topLevelTargetsWithConfigs) {
+          aspectConfigurations.put(
+              Pair.of(targetSpec.getLabel(), aspect), targetSpec.getConfiguration());
+          aspectKeys.add(
+              AspectValueKey.createStarlarkAspectKey(
+                  targetSpec.getLabel(),
+                  // For invoking top-level aspects, use the top-level configuration for both the
+                  // aspect and the base target while the top-level configuration is untrimmed.
+                  targetSpec.getConfiguration(),
+                  targetSpec.getConfiguration(),
+                  starlarkFileLabel,
+                  starlarkFunctionName));
+        }
       } else {
         final NativeAspectClass aspectFactoryClass =
             ruleClassProvider.getNativeAspectClassMap().get(aspect);
 
         if (aspectFactoryClass != null) {
-          aspectClassesBuilder.add(aspectFactoryClass);
+          for (TargetAndConfiguration targetSpec : topLevelTargetsWithConfigs) {
+            // For invoking top-level aspects, use the top-level configuration for both the
+            // aspect and the base target while the top-level configuration is untrimmed.
+            BuildConfiguration configuration = targetSpec.getConfiguration();
+            aspectConfigurations.put(Pair.of(targetSpec.getLabel(), aspect), configuration);
+            aspectKeys.add(
+                AspectValueKey.createAspectKey(
+                    targetSpec.getLabel(),
+                    configuration,
+                    new AspectDescriptor(aspectFactoryClass, AspectParameters.EMPTY),
+                    configuration));
+          }
         } else {
           String errorMessage = "Aspect '" + aspect + "' is unknown";
           throw new ViewCreationFailedException(
@@ -330,25 +358,6 @@
       }
     }
 
-    Multimap<Pair<Label, String>, BuildConfiguration> aspectConfigurations =
-        ArrayListMultimap.create();
-    ImmutableList<AspectClass> aspectClasses = aspectClassesBuilder.build();
-    ImmutableList.Builder<TopLevelAspectsKey> aspectsKeys = ImmutableList.builder();
-    for (TargetAndConfiguration targetSpec : topLevelTargetsWithConfigs) {
-      BuildConfiguration configuration = targetSpec.getConfiguration();
-      for (AspectClass aspectClass : aspectClasses) {
-        aspectConfigurations.put(
-            Pair.of(targetSpec.getLabel(), aspectClass.getName()), configuration);
-      }
-      // For invoking top-level aspects, use the top-level configuration for both the
-      // aspect and the base target while the top-level configuration is untrimmed.
-      if (!aspectClasses.isEmpty()) {
-        aspectsKeys.add(
-            AspectValueKey.createTopLevelAspectsKey(
-                aspectClasses, targetSpec.getLabel(), configuration));
-      }
-    }
-
     for (Pair<Label, String> target : aspectConfigurations.keys()) {
       eventBus.post(
           new AspectConfiguredEvent(
@@ -373,7 +382,7 @@
           skyframeBuildView.configureTargets(
               eventHandler,
               topLevelCtKeys,
-              aspectsKeys.build(),
+              aspectKeys,
               Suppliers.memoize(configurationLookupSupplier),
               topLevelOptions,
               eventBus,
diff --git a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java
index c35d8dd..5dcd758 100644
--- a/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/buildtool/BuildRequestOptions.java
@@ -297,18 +297,11 @@
       effectTags = {OptionEffectTag.UNKNOWN},
       allowMultiple = true,
       help =
-          "Comma-separated list of aspects to be applied to top-level targets. All aspects are"
-              + " applied to all top-level targets. If aspect <code>some_aspect</code> specifies"
-              + " required aspect providers via <code>required_aspect_providers</code>,"
-              + " <code>some_aspect</code> will run after every aspect that was mentioned before it"
-              + " in the aspects list and whose advertised providers satisfy"
-              + " <code>some_aspect</code> required aspect providers. <code>some_aspect</code> will"
-              + " then have access to the values of those aspects' providers. Aspects that do not"
-              + " have such dependency will run independently on the top-level targets."
-              + ""
-              + " Aspects are specified in the form <bzl-file-label>%<aspect_name>, for example"
-              + " '//tools:my_def.bzl%my_aspect', where 'my_aspect' is a top-level value from a"
-              + " file tools/my_def.bzl")
+          "Comma-separated list of aspects to be applied to top-level targets. All aspects "
+              + "are applied to all top-level targets independently. Aspects are specified in "
+              + "the form <bzl-file-label>%<aspect_name>, "
+              + "for example '//tools:my_def.bzl%my_aspect', where 'my_aspect' is a top-level "
+              + "value from from a file tools/my_def.bzl")
   public List<String> aspects;
 
   public BuildRequestOptions() throws OptionsParsingException {}
diff --git a/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspectClass.java b/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspectClass.java
index bf0b414..2b9f2a3 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspectClass.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/StarlarkAspectClass.java
@@ -64,9 +64,4 @@
   public int hashCode() {
     return Objects.hash(extensionLabel, exportedName);
   }
-
-  @Override
-  public String toString() {
-    return getName();
-  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValueKey.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValueKey.java
index f97e08d..04c15bd 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectValueKey.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectValueKey.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
+import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
@@ -29,15 +30,29 @@
 import com.google.devtools.build.skyframe.SkyFunctionName;
 import javax.annotation.Nullable;
 
-/** A wrapper class for sky keys needed to compute sky values for aspects. */
-public final class AspectValueKey {
-
-  private AspectValueKey() {}
+/** A base class for keys that have AspectValue as a Sky value. */
+public abstract class AspectValueKey implements ActionLookupKey {
 
   private static final Interner<AspectKey> aspectKeyInterner = BlazeInterners.newWeakInterner();
-  private static final Interner<TopLevelAspectsKey> topLevelAspectsKeyInterner =
+  private static final Interner<StarlarkAspectLoadingKey> starlarkAspectKeyInterner =
       BlazeInterners.newWeakInterner();
 
+  /**
+   * Gets the name of the aspect that would be returned by the corresponding value's {@code
+   * aspectValue.getAspect().getAspectClass().getName()}, if the value could be produced.
+   *
+   * <p>Only needed for reporting errors in BEP when the key's AspectValue fails evaluation.
+   */
+  public abstract String getAspectName();
+
+  public abstract String getDescription();
+
+  @Nullable
+  abstract BuildConfigurationValue.Key getAspectConfigurationKey();
+
+  /** Returns the key for the base configured target for this aspect. */
+  public abstract ConfiguredTargetKey getBaseConfiguredTargetKey();
+
   public static AspectKey createAspectKey(
       Label label,
       @Nullable BuildConfiguration baseConfiguration,
@@ -72,48 +87,33 @@
         aspectConfiguration == null ? null : BuildConfigurationValue.key(aspectConfiguration));
   }
 
-  public static TopLevelAspectsKey createTopLevelAspectsKey(
-      ImmutableList<AspectClass> topLevelAspectsClasses,
+  public static StarlarkAspectLoadingKey createStarlarkAspectKey(
       Label targetLabel,
-      @Nullable BuildConfiguration configuration) {
-    return TopLevelAspectsKey.createInternal(
-        topLevelAspectsClasses,
+      @Nullable BuildConfiguration aspectConfiguration,
+      @Nullable BuildConfiguration targetConfiguration,
+      Label starlarkFileLabel,
+      String starlarkExportName) {
+    return StarlarkAspectLoadingKey.createInternal(
         targetLabel,
+        aspectConfiguration == null ? null : BuildConfigurationValue.key(aspectConfiguration),
         ConfiguredTargetKey.builder()
             .setLabel(targetLabel)
-            .setConfiguration(configuration)
-            .build());
-  }
-
-  /** Common superclass for {@link AspectKey} and {@link TopLevelAspectsKey}. */
-  public abstract static class AspectBaseKey implements ActionLookupKey {
-    private final ConfiguredTargetKey baseConfiguredTargetKey;
-    private final int hashCode;
-
-    private AspectBaseKey(ConfiguredTargetKey baseConfiguredTargetKey, int hashCode) {
-      this.baseConfiguredTargetKey = baseConfiguredTargetKey;
-      this.hashCode = hashCode;
-    }
-
-    /** Returns the key for the base configured target for this aspect. */
-    public final ConfiguredTargetKey getBaseConfiguredTargetKey() {
-      return baseConfiguredTargetKey;
-    }
-
-    @Override
-    public final int hashCode() {
-      return hashCode;
-    }
+            .setConfiguration(targetConfiguration)
+            .build(),
+        starlarkFileLabel,
+        starlarkExportName);
   }
 
   // Specific subtypes of aspect keys.
 
   /** Represents an aspect applied to a particular target. */
   @AutoCodec
-  public static final class AspectKey extends AspectBaseKey {
+  public static final class AspectKey extends AspectValueKey {
+    private final ConfiguredTargetKey baseConfiguredTargetKey;
     private final ImmutableList<AspectKey> baseKeys;
     @Nullable private final BuildConfigurationValue.Key aspectConfigurationKey;
     private final AspectDescriptor aspectDescriptor;
+    private final int hashCode;
 
     private AspectKey(
         ConfiguredTargetKey baseConfiguredTargetKey,
@@ -121,10 +121,11 @@
         AspectDescriptor aspectDescriptor,
         @Nullable BuildConfigurationValue.Key aspectConfigurationKey,
         int hashCode) {
-      super(baseConfiguredTargetKey, hashCode);
       this.baseKeys = baseKeys;
       this.aspectConfigurationKey = aspectConfigurationKey;
+      this.baseConfiguredTargetKey = baseConfiguredTargetKey;
       this.aspectDescriptor = aspectDescriptor;
+      this.hashCode = hashCode;
     }
 
     @AutoCodec.VisibleForSerialization
@@ -149,19 +150,14 @@
       return SkyFunctions.ASPECT;
     }
 
-    /**
-     * Gets the name of the aspect that would be returned by the corresponding value's {@code
-     * aspectValue.getAspect().getAspectClass().getName()}, if the value could be produced.
-     *
-     * <p>Only needed for reporting errors in BEP when the key's AspectValue fails evaluation.
-     */
+    @Override
     public String getAspectName() {
       return aspectDescriptor.getDescription();
     }
 
     @Override
     public Label getLabel() {
-      return getBaseConfiguredTargetKey().getLabel();
+      return baseConfiguredTargetKey.getLabel();
     }
 
     public AspectClass getAspectClass() {
@@ -191,9 +187,11 @@
       return baseKeys;
     }
 
+    @Override
     public String getDescription() {
       if (baseKeys.isEmpty()) {
-        return String.format("%s of %s", aspectDescriptor.getAspectClass().getName(), getLabel());
+        return String.format("%s of %s",
+            aspectDescriptor.getAspectClass().getName(), getLabel());
       } else {
         return String.format(
             "%s on top of %s", aspectDescriptor.getAspectClass().getName(), baseKeys);
@@ -218,10 +216,22 @@
      * base target's configuration.
      */
     @Nullable
+    @Override
     BuildConfigurationValue.Key getAspectConfigurationKey() {
       return aspectConfigurationKey;
     }
 
+    /** Returns the key for the base configured target for this aspect. */
+    @Override
+    public ConfiguredTargetKey getBaseConfiguredTargetKey() {
+      return baseConfiguredTargetKey;
+    }
+
+    @Override
+    public int hashCode() {
+      return hashCode;
+    }
+
     @Override
     public boolean equals(Object other) {
       if (this == other) {
@@ -231,10 +241,10 @@
         return false;
       }
       AspectKey that = (AspectKey) other;
-      return hashCode() == that.hashCode()
+      return hashCode == that.hashCode
           && Objects.equal(baseKeys, that.baseKeys)
           && Objects.equal(aspectConfigurationKey, that.aspectConfigurationKey)
-          && Objects.equal(getBaseConfiguredTargetKey(), that.getBaseConfiguredTargetKey())
+          && Objects.equal(baseConfiguredTargetKey, that.baseConfiguredTargetKey)
           && Objects.equal(aspectDescriptor, that.aspectDescriptor);
     }
 
@@ -257,7 +267,7 @@
           + " "
           + aspectConfigurationKey
           + " "
-          + getBaseConfiguredTargetKey()
+          + baseConfiguredTargetKey
           + " "
           + aspectDescriptor.getParameters();
     }
@@ -271,7 +281,7 @@
       return createAspectKey(
           ConfiguredTargetKey.builder()
               .setLabel(label)
-              .setConfigurationKey(getBaseConfiguredTargetKey().getConfigurationKey())
+              .setConfigurationKey(baseConfiguredTargetKey.getConfigurationKey())
               .build(),
           newBaseKeys.build(),
           aspectDescriptor,
@@ -279,43 +289,70 @@
     }
   }
 
-  /** The key for top level aspects specified by --aspects option on a top level target. */
+  /** The key for a Starlark aspect. */
   @AutoCodec
-  public static final class TopLevelAspectsKey extends AspectBaseKey {
-    private final ImmutableList<AspectClass> topLevelAspectsClasses;
+  public static final class StarlarkAspectLoadingKey extends AspectValueKey {
     private final Label targetLabel;
+    private final BuildConfigurationValue.Key aspectConfigurationKey;
+    private final ConfiguredTargetKey baseConfiguredTargetKey;
+    private final Label starlarkFileLabel;
+    private final String starlarkValueName;
+    private final int hashCode;
 
     @AutoCodec.Instantiator
     @AutoCodec.VisibleForSerialization
-    static TopLevelAspectsKey createInternal(
-        ImmutableList<AspectClass> topLevelAspectsClasses,
+    static StarlarkAspectLoadingKey createInternal(
         Label targetLabel,
-        ConfiguredTargetKey baseConfiguredTargetKey) {
-      return topLevelAspectsKeyInterner.intern(
-          new TopLevelAspectsKey(
-              topLevelAspectsClasses,
+        BuildConfigurationValue.Key aspectConfigurationKey,
+        ConfiguredTargetKey baseConfiguredTargetKey,
+        Label starlarkFileLabel,
+        String starlarkValueName) {
+      return starlarkAspectKeyInterner.intern(
+          new StarlarkAspectLoadingKey(
               targetLabel,
+              aspectConfigurationKey,
               baseConfiguredTargetKey,
-              Objects.hashCode(topLevelAspectsClasses, targetLabel, baseConfiguredTargetKey)));
+              starlarkFileLabel,
+              starlarkValueName,
+              Objects.hashCode(
+                  targetLabel,
+                  aspectConfigurationKey,
+                  baseConfiguredTargetKey,
+                  starlarkFileLabel,
+                  starlarkValueName)));
     }
 
-    private TopLevelAspectsKey(
-        ImmutableList<AspectClass> topLevelAspectsClasses,
+    private StarlarkAspectLoadingKey(
         Label targetLabel,
+        BuildConfigurationValue.Key aspectConfigurationKey,
         ConfiguredTargetKey baseConfiguredTargetKey,
+        Label starlarkFileLabel,
+        String starlarkValueName,
         int hashCode) {
-      super(baseConfiguredTargetKey, hashCode);
-      this.topLevelAspectsClasses = topLevelAspectsClasses;
       this.targetLabel = targetLabel;
+      this.aspectConfigurationKey = aspectConfigurationKey;
+      this.baseConfiguredTargetKey = baseConfiguredTargetKey;
+      this.starlarkFileLabel = starlarkFileLabel;
+      this.starlarkValueName = starlarkValueName;
+      this.hashCode = hashCode;
     }
 
     @Override
     public SkyFunctionName functionName() {
-      return SkyFunctions.TOP_LEVEL_ASPECTS;
+      return SkyFunctions.LOAD_STARLARK_ASPECT;
     }
 
-    ImmutableList<AspectClass> getTopLevelAspectsClasses() {
-      return topLevelAspectsClasses;
+    String getStarlarkValueName() {
+      return starlarkValueName;
+    }
+
+    Label getStarlarkFileLabel() {
+      return starlarkFileLabel;
+    }
+
+    @Override
+    public String getAspectName() {
+      return String.format("%s%%%s", starlarkFileLabel, starlarkValueName);
     }
 
     @Override
@@ -323,8 +360,27 @@
       return targetLabel;
     }
 
-    String getDescription() {
-      return topLevelAspectsClasses + " on " + getLabel();
+    @Override
+    public String getDescription() {
+      // Starlark aspects are referred to on command line with <file>%<value ame>
+      return String.format("%s%%%s of %s", starlarkFileLabel, starlarkValueName, targetLabel);
+    }
+
+    @Nullable
+    @Override
+    BuildConfigurationValue.Key getAspectConfigurationKey() {
+      return aspectConfigurationKey;
+    }
+
+    /** Returns the key for the base configured target for this aspect. */
+    @Override
+    public ConfiguredTargetKey getBaseConfiguredTargetKey() {
+      return baseConfiguredTargetKey;
+    }
+
+    @Override
+    public int hashCode() {
+      return hashCode;
     }
 
     @Override
@@ -332,14 +388,35 @@
       if (o == this) {
         return true;
       }
-      if (!(o instanceof TopLevelAspectsKey)) {
+      if (!(o instanceof StarlarkAspectLoadingKey)) {
         return false;
       }
-      TopLevelAspectsKey that = (TopLevelAspectsKey) o;
-      return hashCode() == that.hashCode()
+      StarlarkAspectLoadingKey that = (StarlarkAspectLoadingKey) o;
+      return hashCode == that.hashCode
           && Objects.equal(targetLabel, that.targetLabel)
-          && Objects.equal(getBaseConfiguredTargetKey(), that.getBaseConfiguredTargetKey())
-          && Objects.equal(topLevelAspectsClasses, that.topLevelAspectsClasses);
+          && Objects.equal(aspectConfigurationKey, that.aspectConfigurationKey)
+          && Objects.equal(baseConfiguredTargetKey, that.baseConfiguredTargetKey)
+          && Objects.equal(starlarkFileLabel, that.starlarkFileLabel)
+          && Objects.equal(starlarkValueName, that.starlarkValueName);
+    }
+
+    @Override
+    public String toString() {
+      return MoreObjects.toStringHelper(this)
+          .add("targetLabel", targetLabel)
+          .add("aspectConfigurationKey", aspectConfigurationKey)
+          .add("baseConfiguredTargetKey", baseConfiguredTargetKey)
+          .add("starlarkFileLabel", starlarkFileLabel)
+          .add("starlarkValueName", starlarkValueName)
+          .toString();
+    }
+
+    AspectKey toAspectKey(AspectClass aspectClass) {
+      return AspectKey.createAspectKey(
+          baseConfiguredTargetKey,
+          ImmutableList.of(),
+          new AspectDescriptor(aspectClass, AspectParameters.EMPTY),
+          aspectConfigurationKey);
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index 9e9a99a..15222d2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -38,7 +38,6 @@
         "ExternalFilesHelper.java",
         "ExternalPackageFunction.java",
         "FileStateFunction.java",
-        "LoadStarlarkAspectFunction.java",
         "LocalRepositoryLookupFunction.java",
         "NonRuleConfiguredTargetValue.java",
         "PackageFunction.java",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/LoadStarlarkAspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/LoadStarlarkAspectFunction.java
deleted file mode 100644
index 4d81910..0000000
--- a/src/main/java/com/google/devtools/build/lib/skyframe/LoadStarlarkAspectFunction.java
+++ /dev/null
@@ -1,169 +0,0 @@
-// Copyright 2021 The Bazel Authors. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//    http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.devtools.build.lib.skyframe;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.Interner;
-import com.google.devtools.build.lib.causes.LabelCause;
-import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.concurrent.BlazeInterners;
-import com.google.devtools.build.lib.packages.StarlarkAspect;
-import com.google.devtools.build.lib.packages.StarlarkAspectClass;
-import com.google.devtools.build.lib.server.FailureDetails.Analysis;
-import com.google.devtools.build.lib.server.FailureDetails.Analysis.Code;
-import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
-import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
-import com.google.devtools.build.lib.util.DetailedExitCode;
-import com.google.devtools.build.skyframe.SkyFunction;
-import com.google.devtools.build.skyframe.SkyFunctionException;
-import com.google.devtools.build.skyframe.SkyFunctionName;
-import com.google.devtools.build.skyframe.SkyKey;
-import com.google.devtools.build.skyframe.SkyValue;
-import javax.annotation.Nullable;
-
-/**
- * SkyFunction to load aspects from Starlark extensions and return StarlarkAspect.
- *
- * <p>Used for loading top-level aspects. At top level, in {@link
- * com.google.devtools.build.lib.analysis.BuildView}, we cannot invoke two SkyFunctions one after
- * another, so BuildView calls this function to do the work.
- */
-public class LoadStarlarkAspectFunction implements SkyFunction {
-  private static final Interner<StarlarkAspectLoadingKey> starlarkAspectLoadingKeyInterner =
-      BlazeInterners.newWeakInterner();
-
-  LoadStarlarkAspectFunction() {}
-
-  @Nullable
-  @Override
-  public SkyValue compute(SkyKey skyKey, Environment env)
-      throws LoadStarlarkAspectFunctionException, InterruptedException {
-    StarlarkAspectLoadingKey aspectLoadingKey = (StarlarkAspectLoadingKey) skyKey.argument();
-
-    Label extensionLabel = aspectLoadingKey.getAspectClass().getExtensionLabel();
-    String exportedName = aspectLoadingKey.getAspectClass().getExportedName();
-    StarlarkAspect starlarkAspect;
-    try {
-      starlarkAspect = AspectFunction.loadStarlarkAspect(env, extensionLabel, exportedName);
-      if (starlarkAspect == null) {
-        return null;
-      }
-      if (!starlarkAspect.getParamAttributes().isEmpty()) {
-        String msg =
-            String.format(
-                "Cannot instantiate parameterized aspect %s at the top level.",
-                starlarkAspect.getName());
-        throw new AspectCreationException(
-            msg,
-            new LabelCause(
-                extensionLabel,
-                createDetailedCode(msg, Code.PARAMETERIZED_TOP_LEVEL_ASPECT_INVALID)));
-      }
-    } catch (AspectCreationException e) {
-      throw new LoadStarlarkAspectFunctionException(e);
-    }
-
-    return new StarlarkAspectLoadingValue(starlarkAspect);
-  }
-
-  @Nullable
-  @Override
-  public String extractTag(SkyKey skyKey) {
-    return null;
-  }
-
-  private static DetailedExitCode createDetailedCode(String msg, Code code) {
-    return DetailedExitCode.of(
-        FailureDetail.newBuilder()
-            .setMessage(msg)
-            .setAnalysis(Analysis.newBuilder().setCode(code))
-            .build());
-  }
-
-  /** Exceptions thrown from LoadStarlarkAspectFunction. */
-  public static class LoadStarlarkAspectFunctionException extends SkyFunctionException {
-    public LoadStarlarkAspectFunctionException(AspectCreationException cause) {
-      super(cause, Transience.PERSISTENT);
-    }
-  }
-
-  public static StarlarkAspectLoadingKey createStarlarkAspectLoadingKey(
-      StarlarkAspectClass aspectClass) {
-    return StarlarkAspectLoadingKey.createInternal(aspectClass);
-  }
-
-  /** Skykey for loading Starlark aspect. */
-  @AutoCodec
-  public static final class StarlarkAspectLoadingKey implements SkyKey {
-    private final StarlarkAspectClass aspectClass;
-    private final int hashCode;
-
-    @AutoCodec.Instantiator
-    @AutoCodec.VisibleForSerialization
-    static StarlarkAspectLoadingKey createInternal(StarlarkAspectClass aspectClass) {
-      return starlarkAspectLoadingKeyInterner.intern(
-          new StarlarkAspectLoadingKey(aspectClass, java.util.Objects.hashCode(aspectClass)));
-    }
-
-    private StarlarkAspectLoadingKey(StarlarkAspectClass aspectClass, int hashCode) {
-      this.aspectClass = aspectClass;
-      this.hashCode = hashCode;
-    }
-
-    @Override
-    public SkyFunctionName functionName() {
-      return SkyFunctions.LOAD_STARLARK_ASPECT;
-    }
-
-    StarlarkAspectClass getAspectClass() {
-      return aspectClass;
-    }
-
-    @Override
-    public int hashCode() {
-      return hashCode;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (o == this) {
-        return true;
-      }
-      if (!(o instanceof StarlarkAspectLoadingKey)) {
-        return false;
-      }
-      StarlarkAspectLoadingKey that = (StarlarkAspectLoadingKey) o;
-      return hashCode == that.hashCode && Objects.equal(aspectClass, that.aspectClass);
-    }
-
-    @Override
-    public String toString() {
-      return aspectClass.toString();
-    }
-  }
-
-  /** SkyValue for {@code StarlarkAspectLoadingKey} holds the loaded {@code StarlarkAspect}. */
-  public static class StarlarkAspectLoadingValue implements SkyValue {
-    private final StarlarkAspect starlarkAspect;
-
-    public StarlarkAspectLoadingValue(StarlarkAspect starlarkAspect) {
-      this.starlarkAspect = starlarkAspect;
-    }
-
-    public StarlarkAspect getAspect() {
-      return starlarkAspect;
-    }
-  }
-}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
index 46443e4..cb07796 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyFunctions.java
@@ -88,8 +88,6 @@
   public static final SkyFunctionName ASPECT = SkyFunctionName.createHermetic("ASPECT");
   static final SkyFunctionName LOAD_STARLARK_ASPECT =
       SkyFunctionName.createHermetic("LOAD_STARLARK_ASPECT");
-  static final SkyFunctionName TOP_LEVEL_ASPECTS =
-      SkyFunctionName.createHermetic("TOP_LEVEL_ASPECTS");
   public static final SkyFunctionName TARGET_COMPLETION =
       SkyFunctionName.create(
           "TARGET_COMPLETION", ShareabilityOfValue.NEVER, FunctionHermeticity.HERMETIC);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
index 792dc66..c718762 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeBuildView.java
@@ -88,9 +88,7 @@
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.skyframe.ArtifactConflictFinder.ConflictException;
 import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.TopLevelAspectsKey;
 import com.google.devtools.build.lib.skyframe.SkyframeExecutor.TopLevelActionConflictReport;
-import com.google.devtools.build.lib.skyframe.ToplevelStarlarkAspectFunction.TopLevelAspectsValue;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.OrderedSetMultimap;
 import com.google.devtools.build.lib.util.Pair;
@@ -382,7 +380,7 @@
   public SkyframeAnalysisResult configureTargets(
       ExtendedEventHandler eventHandler,
       List<ConfiguredTargetKey> ctKeys,
-      ImmutableList<TopLevelAspectsKey> topLevelAspectsKey,
+      List<AspectValueKey> aspectKeys,
       Supplier<Map<BuildConfigurationValue.Key, BuildConfiguration>> configurationLookupSupplier,
       TopLevelArtifactContext topLevelArtifactContextForConflictPruning,
       EventBus eventBus,
@@ -399,7 +397,7 @@
           skyframeExecutor.configureTargets(
               eventHandler,
               ctKeys,
-              topLevelAspectsKey,
+              aspectKeys,
               keepGoing,
               numThreads,
               cpuHeavySkyKeysThreadPoolSize);
@@ -407,33 +405,21 @@
       enableAnalysis(false);
     }
 
-    int numOfAspects = 0;
-    if (!topLevelAspectsKey.isEmpty()) {
-      numOfAspects =
-          topLevelAspectsKey.size() * topLevelAspectsKey.get(0).getTopLevelAspectsClasses().size();
-    }
-    Map<AspectKey, ConfiguredAspect> aspects = Maps.newHashMapWithExpectedSize(numOfAspects);
+    Map<AspectKey, ConfiguredAspect> aspects = Maps.newHashMapWithExpectedSize(aspectKeys.size());
     Root singleSourceRoot = skyframeExecutor.getForcedSingleSourceRootIfNoExecrootSymlinkCreation();
     NestedSetBuilder<Package> packages =
         singleSourceRoot == null ? NestedSetBuilder.stableOrder() : null;
-    ImmutableList.Builder<AspectKey> aspectKeysBuilder = ImmutableList.builder();
-
-    for (TopLevelAspectsKey key : topLevelAspectsKey) {
-      TopLevelAspectsValue value = (TopLevelAspectsValue) result.get(key);
+    for (AspectValueKey aspectKey : aspectKeys) {
+      AspectValue value = (AspectValue) result.get(aspectKey);
       if (value == null) {
         // Skip aspects that couldn't be applied to targets.
         continue;
       }
-      for (SkyValue val : value.getTopLevelAspectsValues()) {
-        AspectValue aspectValue = (AspectValue) val;
-        aspects.put(aspectValue.getKey(), aspectValue.getConfiguredAspect());
-        if (packages != null) {
-          packages.addTransitive(aspectValue.getTransitivePackagesForPackageRootResolution());
-        }
-        aspectKeysBuilder.add(aspectValue.getKey());
+      aspects.put(value.getKey(), value.getConfiguredAspect());
+      if (packages != null) {
+        packages.addTransitive(value.getTransitivePackagesForPackageRootResolution());
       }
     }
-    ImmutableList<AspectKey> aspectKeys = aspectKeysBuilder.build();
 
     Collection<ConfiguredTarget> cts = Lists.newArrayListWithCapacity(ctKeys.size());
     for (ConfiguredTargetKey value : ctKeys) {
@@ -575,7 +561,7 @@
           BuildConfigurationValue.Key configKey =
               ctKey instanceof ConfiguredTargetKey
                   ? ((ConfiguredTargetKey) ctKey).getConfigurationKey()
-                  : ((AspectKey) ctKey).getAspectConfigurationKey();
+                  : ((AspectValueKey) ctKey).getAspectConfigurationKey();
           eventBus.post(
               new AnalysisFailureEvent(
                   ctKey,
@@ -611,9 +597,13 @@
               .collect(toImmutableList());
 
       aspects =
-          aspects.entrySet().stream()
-              .filter(e -> topLevelActionConflictReport.isErrorFree(e.getKey()))
-              .collect(ImmutableMap.toImmutableMap(Map.Entry::getKey, Map.Entry::getValue));
+          aspectKeys.stream()
+              .filter(topLevelActionConflictReport::isErrorFree)
+              .map(result::get)
+              .map(AspectValue.class::cast)
+              .collect(
+                  ImmutableMap.toImmutableMap(
+                      AspectValue::getKey, AspectValue::getConfiguredAspect));
     }
 
     return new SkyframeAnalysisResult(
@@ -755,15 +745,17 @@
           .reportCycles(errorInfo.getCycleInfo(), errorKey, eventHandler);
       Exception cause = errorInfo.getException();
       Preconditions.checkState(cause != null || !errorInfo.getCycleInfo().isEmpty(), errorInfo);
-      if (errorKey.argument() instanceof TopLevelAspectsKey) {
+
+      if (errorKey.argument() instanceof AspectValueKey) {
         // We skip Aspects in the keepGoing case; the failures should already have been reported to
         // the event handler.
         if (!keepGoing && noKeepGoingException == null) {
-          TopLevelAspectsKey aspectKey = (TopLevelAspectsKey) errorKey.argument();
+          AspectValueKey aspectKey = (AspectValueKey) errorKey.argument();
           failedAspectLabel = aspectKey.getBaseConfiguredTargetKey();
+
           String errorMsg =
               String.format(
-                  "Analysis of aspects '%s' failed; build aborted", aspectKey.getDescription());
+                  "Analysis of aspect '%s' failed; build aborted", aspectKey.getDescription());
           noKeepGoingException = createViewCreationFailedException(cause, errorMsg);
         }
         continue;
@@ -784,7 +776,7 @@
       }
       Preconditions.checkState(
           errorKey.argument() instanceof ConfiguredTargetKey,
-          "expected '%s' to be a TopLevelAspectsKey or ConfiguredTargetKey",
+          "expected '%s' to be a AspectValueKey or ConfiguredTargetKey",
           errorKey.argument());
       ConfiguredTargetKey label = (ConfiguredTargetKey) errorKey.argument();
       Label topLevelLabel = label.getLabel();
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
index 780cdce..af7eb27 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/SkyframeExecutor.java
@@ -162,7 +162,6 @@
 import com.google.devtools.build.lib.server.FailureDetails.TargetPatterns;
 import com.google.devtools.build.lib.skyframe.ArtifactConflictFinder.ConflictException;
 import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.TopLevelAspectsKey;
 import com.google.devtools.build.lib.skyframe.DirtinessCheckerUtils.FileDirtinessChecker;
 import com.google.devtools.build.lib.skyframe.ExternalFilesHelper.ExternalFileAction;
 import com.google.devtools.build.lib.skyframe.MetadataConsumerForMetrics.FilesMetricConsumer;
@@ -575,8 +574,7 @@
             new BuildViewProvider(),
             ruleClassProvider,
             shouldStoreTransitivePackagesInLoadingAndAnalysis()));
-    map.put(SkyFunctions.LOAD_STARLARK_ASPECT, new LoadStarlarkAspectFunction());
-    map.put(SkyFunctions.TOP_LEVEL_ASPECTS, new ToplevelStarlarkAspectFunction());
+    map.put(SkyFunctions.LOAD_STARLARK_ASPECT, new ToplevelStarlarkAspectFunction());
     map.put(SkyFunctions.ACTION_LOOKUP_CONFLICT_FINDING, new ActionLookupConflictFindingFunction());
     map.put(
         SkyFunctions.TOP_LEVEL_ACTION_LOOKUP_CONFLICT_FINDING,
@@ -2334,7 +2332,7 @@
   EvaluationResult<ActionLookupValue> configureTargets(
       ExtendedEventHandler eventHandler,
       List<ConfiguredTargetKey> values,
-      ImmutableList<TopLevelAspectsKey> aspectKeys,
+      List<AspectValueKey> aspectKeys,
       boolean keepGoing,
       int numThreads,
       int cpuHeavySkyKeysThreadPoolSize)
@@ -3071,7 +3069,7 @@
   }
 
   final AnalysisTraversalResult getActionLookupValuesInBuild(
-      List<ConfiguredTargetKey> topLevelCtKeys, ImmutableList<AspectKey> aspectKeys)
+      List<ConfiguredTargetKey> topLevelCtKeys, List<AspectValueKey> aspectKeys)
       throws InterruptedException {
     AnalysisTraversalResult result = new AnalysisTraversalResult();
     if (!isAnalysisIncremental()) {
@@ -3091,7 +3089,7 @@
     for (ConfiguredTargetKey key : topLevelCtKeys) {
       findActionsRecursively(walkableGraph, key, seen, result);
     }
-    for (AspectKey key : aspectKeys) {
+    for (AspectValueKey key : aspectKeys) {
       findActionsRecursively(walkableGraph, key, seen, result);
     }
     return result;
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/TargetCycleReporter.java b/src/main/java/com/google/devtools/build/lib/skyframe/TargetCycleReporter.java
index 693bde7..cf8f828 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/TargetCycleReporter.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/TargetCycleReporter.java
@@ -39,7 +39,7 @@
       Predicates.or(
           SkyFunctions.isSkyFunction(SkyFunctions.CONFIGURED_TARGET),
           SkyFunctions.isSkyFunction(SkyFunctions.ASPECT),
-          SkyFunctions.isSkyFunction(SkyFunctions.TOP_LEVEL_ASPECTS),
+          SkyFunctions.isSkyFunction(SkyFunctions.LOAD_STARLARK_ASPECT),
           SkyFunctions.isSkyFunction(TransitiveTargetKey.NAME),
           SkyFunctions.isSkyFunction(SkyFunctions.PREPARE_ANALYSIS_PHASE));
 
@@ -65,6 +65,8 @@
       return ((ConfiguredTargetKey) key.argument()).prettyPrint();
     } else if (key instanceof AspectKey) {
       return ((AspectKey) key.argument()).prettyPrint();
+    } else if (key instanceof AspectValueKey) {
+      return ((AspectValueKey) key).getDescription();
     } else {
       return getLabel(key).toString();
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ToplevelStarlarkAspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ToplevelStarlarkAspectFunction.java
index 5638d8e..a858e35 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ToplevelStarlarkAspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ToplevelStarlarkAspectFunction.java
@@ -14,36 +14,22 @@
 
 package com.google.devtools.build.lib.skyframe;
 
-import com.google.common.collect.ImmutableList;
-import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
-import com.google.devtools.build.lib.actions.ActionLookupValue;
-import com.google.devtools.build.lib.analysis.AspectCollection;
-import com.google.devtools.build.lib.analysis.AspectCollection.AspectCycleOnPathException;
-import com.google.devtools.build.lib.events.Event;
-import com.google.devtools.build.lib.packages.Aspect;
-import com.google.devtools.build.lib.packages.AspectClass;
-import com.google.devtools.build.lib.packages.AspectDescriptor;
-import com.google.devtools.build.lib.packages.AspectsListBuilder;
-import com.google.devtools.build.lib.packages.NativeAspectClass;
+import com.google.devtools.build.lib.causes.LabelCause;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.StarlarkAspect;
-import com.google.devtools.build.lib.packages.StarlarkAspectClass;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.AspectKey;
-import com.google.devtools.build.lib.skyframe.AspectValueKey.TopLevelAspectsKey;
-import com.google.devtools.build.lib.skyframe.LoadStarlarkAspectFunction.StarlarkAspectLoadingKey;
-import com.google.devtools.build.lib.skyframe.LoadStarlarkAspectFunction.StarlarkAspectLoadingValue;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis.Code;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
+import com.google.devtools.build.lib.skyframe.AspectValueKey.StarlarkAspectLoadingKey;
+import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.skyframe.SkyFunction;
 import com.google.devtools.build.skyframe.SkyFunctionException;
 import com.google.devtools.build.skyframe.SkyKey;
 import com.google.devtools.build.skyframe.SkyValue;
-import java.util.HashMap;
-import java.util.Map;
 import javax.annotation.Nullable;
-import net.starlark.java.eval.EvalException;
 
 /**
- * SkyFunction to load top level aspects, build the dependency relation between them based on the
- * providers they advertise and provide using {@link AspectCollection} and runs the obtained aspects
- * path on the top level target.
+ * SkyFunction to load aspects from Starlark extensions and calculate their values.
  *
  * <p>Used for loading top-level aspects. At top level, in {@link
  * com.google.devtools.build.lib.analysis.BuildView}, we cannot invoke two SkyFunctions one after
@@ -55,40 +41,34 @@
   @Nullable
   @Override
   public SkyValue compute(SkyKey skyKey, Environment env)
-      throws TopLevelStarlarkAspectFunctionException, InterruptedException {
-    TopLevelAspectsKey topLevelAspectsKey = (TopLevelAspectsKey) skyKey.argument();
+      throws LoadStarlarkAspectFunctionException, InterruptedException {
+    StarlarkAspectLoadingKey aspectLoadingKey = (StarlarkAspectLoadingKey) skyKey.argument();
+    String starlarkValueName = aspectLoadingKey.getStarlarkValueName();
+    Label starlarkFileLabel = aspectLoadingKey.getStarlarkFileLabel();
 
-    ImmutableList<Aspect> topLevelAspects;
+    StarlarkAspect starlarkAspect;
     try {
-      topLevelAspects = getTopLevelAspects(env, topLevelAspectsKey.getTopLevelAspectsClasses());
-    } catch (EvalException e) {
-      env.getListener().handle(Event.error(e.getMessage()));
-      throw new TopLevelStarlarkAspectFunctionException(
-          new AspectCreationException(e.getMessage(), topLevelAspectsKey.getLabel()));
+      starlarkAspect = AspectFunction.loadStarlarkAspect(env, starlarkFileLabel, starlarkValueName);
+      if (starlarkAspect == null) {
+        return null;
+      }
+      if (!starlarkAspect.getParamAttributes().isEmpty()) {
+        String msg =
+            String.format(
+                "Cannot instantiate parameterized aspect %s at the top level.",
+                starlarkAspect.getName());
+        throw new AspectCreationException(
+            msg,
+            new LabelCause(
+                starlarkFileLabel,
+                createDetailedCode(msg, Code.PARAMETERIZED_TOP_LEVEL_ASPECT_INVALID)));
+      }
+    } catch (AspectCreationException e) {
+      throw new LoadStarlarkAspectFunctionException(e);
     }
+    SkyKey aspectKey = aspectLoadingKey.toAspectKey(starlarkAspect.getAspectClass());
 
-    if (topLevelAspects == null) {
-      return null; // some aspects are not loaded
-    }
-
-    AspectCollection aspectCollection;
-    try {
-      aspectCollection = AspectCollection.create(topLevelAspects);
-    } catch (AspectCycleOnPathException e) {
-      env.getListener().handle(Event.error(e.getMessage()));
-      throw new TopLevelStarlarkAspectFunctionException(
-          new AspectCreationException(e.getMessage(), topLevelAspectsKey.getLabel()));
-    }
-
-    ImmutableList<AspectKey> aspectKeys =
-        getTopLevelAspectsKeys(aspectCollection, topLevelAspectsKey.getBaseConfiguredTargetKey());
-
-    Map<SkyKey, SkyValue> result = env.getValues(aspectKeys);
-    if (env.valuesMissing()) {
-      return null; // some aspects keys are not evaluated
-    }
-
-    return new TopLevelAspectsValue(result);
+    return env.getValue(aspectKey);
   }
 
   @Nullable
@@ -97,112 +77,18 @@
     return null;
   }
 
-  @Nullable
-  private static ImmutableList<Aspect> getTopLevelAspects(
-      Environment env, ImmutableList<AspectClass> topLevelAspectsClasses)
-      throws InterruptedException, EvalException {
-    AspectsListBuilder aspectsList = new AspectsListBuilder();
-
-    ImmutableList.Builder<StarlarkAspectLoadingKey> aspectLoadingKeys = ImmutableList.builder();
-    for (AspectClass aspectClass : topLevelAspectsClasses) {
-      if (aspectClass instanceof StarlarkAspectClass) {
-        aspectLoadingKeys.add(
-            LoadStarlarkAspectFunction.createStarlarkAspectLoadingKey(
-                (StarlarkAspectClass) aspectClass));
-      }
-    }
-
-    Map<SkyKey, SkyValue> loadedAspects = env.getValues(aspectLoadingKeys.build());
-    if (env.valuesMissing()) {
-      return null;
-    }
-
-    for (AspectClass aspectClass : topLevelAspectsClasses) {
-      if (aspectClass instanceof StarlarkAspectClass) {
-        StarlarkAspectLoadingValue aspectLoadingValue =
-            (StarlarkAspectLoadingValue)
-                loadedAspects.get(
-                    LoadStarlarkAspectFunction.createStarlarkAspectLoadingKey(
-                        (StarlarkAspectClass) aspectClass));
-        StarlarkAspect starlarkAspect = aspectLoadingValue.getAspect();
-        starlarkAspect.attachToAspectsList(
-            /** baseAspectName= */
-            null,
-            aspectsList,
-            /** inheritedRequiredProviders= */
-            ImmutableList.of(),
-            /** inheritedAttributeAspects= */
-            ImmutableList.of());
-      } else {
-        aspectsList.addAspect((NativeAspectClass) aspectClass);
-      }
-    }
-
-    return aspectsList.buildAspects();
-  }
-
-  private static ImmutableList<AspectKey> getTopLevelAspectsKeys(
-      AspectCollection aspectCollection, ConfiguredTargetKey topLevelTargetKey) {
-    Map<AspectDescriptor, AspectKey> result = new HashMap<>();
-    for (AspectCollection.AspectDeps aspectDeps : aspectCollection.getUsedAspects()) {
-      buildAspectKey(aspectDeps, result, topLevelTargetKey);
-    }
-    return ImmutableList.copyOf(result.values());
-  }
-
-  private static AspectKey buildAspectKey(
-      AspectCollection.AspectDeps aspectDeps,
-      Map<AspectDescriptor, AspectKey> result,
-      ConfiguredTargetKey topLevelTargetKey) {
-    if (result.containsKey(aspectDeps.getAspect())) {
-      return result.get(aspectDeps.getAspect());
-    }
-
-    ImmutableList.Builder<AspectKey> dependentAspects = ImmutableList.builder();
-    for (AspectCollection.AspectDeps path : aspectDeps.getUsedAspects()) {
-      dependentAspects.add(buildAspectKey(path, result, topLevelTargetKey));
-    }
-
-    AspectKey aspectKey =
-        AspectValueKey.createAspectKey(
-            aspectDeps.getAspect(),
-            dependentAspects.build(),
-            topLevelTargetKey.getConfigurationKey(),
-            topLevelTargetKey);
-    result.put(aspectKey.getAspectDescriptor(), aspectKey);
-    return aspectKey;
+  private static DetailedExitCode createDetailedCode(String msg, Code code) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setMessage(msg)
+            .setAnalysis(Analysis.newBuilder().setCode(code))
+            .build());
   }
 
   /** Exceptions thrown from ToplevelStarlarkAspectFunction. */
-  public static class TopLevelStarlarkAspectFunctionException extends SkyFunctionException {
-    public TopLevelStarlarkAspectFunctionException(AspectCreationException cause) {
+  public static class LoadStarlarkAspectFunctionException extends SkyFunctionException {
+    public LoadStarlarkAspectFunctionException(AspectCreationException cause) {
       super(cause, Transience.PERSISTENT);
     }
   }
-
-  /**
-   * SkyValue for {@code TopLevelAspectsKey} wraps a list of the {@code AspectValue} of the top
-   * level aspects applied on the same top level target.
-   */
-  public static class TopLevelAspectsValue implements ActionLookupValue {
-    private final Map<SkyKey, SkyValue> topLevelAspectsMap;
-
-    public TopLevelAspectsValue(Map<SkyKey, SkyValue> topLevelAspectsMap) {
-      this.topLevelAspectsMap = topLevelAspectsMap;
-    }
-
-    public ImmutableList<SkyValue> getTopLevelAspectsValues() {
-      return ImmutableList.copyOf(topLevelAspectsMap.values());
-    }
-
-    public SkyValue get(SkyKey skyKey) {
-      return topLevelAspectsMap.get(skyKey);
-    }
-
-    @Override
-    public ImmutableList<ActionAnalysisMetadata> getActions() {
-      // return topLevelAspectsMap.values().stream().
-      return ImmutableList.of();
-    }
-  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
index e6e5929..e39c708 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectTest.java
@@ -875,25 +875,20 @@
   }
 
   @Test
-  public void duplicateAspectsFailed() throws Exception {
+  public void duplicateAspectsDeduped() throws Exception {
     AspectApplyingToFiles aspectApplyingToFiles = new AspectApplyingToFiles();
     setRulesAndAspectsAvailableInTests(ImmutableList.of(aspectApplyingToFiles), ImmutableList.of());
     pkg("a", "java_binary(name = 'x', main_class = 'x.FooBar', srcs = ['x.java'])");
-    reporter.removeHandler(failFastHandler);
-    AssertionError exception =
-        assertThrows(
-            AssertionError.class,
-            () ->
-                update(
-                    new EventBus(),
-                    defaultFlags(),
-                    ImmutableList.of(
-                        aspectApplyingToFiles.getName(), aspectApplyingToFiles.getName()),
-                    "//a:x_deploy.jar"));
-
-    assertThat(exception)
-        .hasMessageThat()
-        .containsMatch("Aspect AspectApplyingToFiles has already been added");
+    AnalysisResult analysisResult =
+        update(
+            new EventBus(),
+            defaultFlags(),
+            ImmutableList.of(aspectApplyingToFiles.getName(), aspectApplyingToFiles.getName()),
+            "//a:x_deploy.jar");
+    ConfiguredAspect aspect = Iterables.getOnlyElement(analysisResult.getAspectsMap().values());
+    AspectApplyingToFiles.Provider provider =
+        aspect.getProvider(AspectApplyingToFiles.Provider.class);
+    assertThat(provider.getLabel()).isEqualTo(Label.parseAbsoluteUnchecked("//a:x_deploy.jar"));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/TargetCycleReporterTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/TargetCycleReporterTest.java
index f491bea..17ec740 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/TargetCycleReporterTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/TargetCycleReporterTest.java
@@ -18,7 +18,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.packages.StarlarkAspectClass;
 import com.google.devtools.build.skyframe.CycleInfo;
 import com.google.devtools.build.skyframe.SkyKey;
 import org.junit.Test;
@@ -71,12 +70,12 @@
                 + "target //foo:c");
 
     SkyKey starlarkAspectKey =
-        AspectValueKey.createTopLevelAspectsKey(
-            ImmutableList.of(
-                new StarlarkAspectClass(
-                    Label.parseAbsoluteUnchecked("//foo:b"), "my Starlark key")),
+        AspectValueKey.createStarlarkAspectKey(
             Label.parseAbsoluteUnchecked("//foo:a"),
-            targetConfig);
+            targetConfig,
+            targetConfig,
+            Label.parseAbsoluteUnchecked("//foo:b"),
+            "my Starlark key");
     assertThat(cycleReporter.getAdditionalMessageAboutCycle(reporter, starlarkAspectKey, cycle))
         .contains(
             "The cycle is caused by a visibility edge from //foo:b to the non-package_group "
diff --git a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkDefinedAspectsTest.java b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkDefinedAspectsTest.java
index 375e8a8..e74bb4d 100644
--- a/src/test/java/com/google/devtools/build/lib/starlark/StarlarkDefinedAspectsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/starlark/StarlarkDefinedAspectsTest.java
@@ -40,7 +40,6 @@
 import com.google.devtools.build.lib.collect.nestedset.Depset;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.packages.AspectDefinition;
-import com.google.devtools.build.lib.packages.StarlarkAspectClass;
 import com.google.devtools.build.lib.packages.StarlarkProvider;
 import com.google.devtools.build.lib.packages.StructImpl;
 import com.google.devtools.build.lib.rules.cpp.CppConfiguration;
@@ -53,7 +52,6 @@
 import com.google.devtools.build.lib.vfs.Path;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
 import net.starlark.java.eval.Sequence;
 import net.starlark.java.eval.Starlark;
 import net.starlark.java.eval.StarlarkInt;
@@ -4197,1287 +4195,6 @@
     assertThat(aspectBResult).isEqualTo("aspect_b on target //test:dep_target cannot find prov_b");
   }
 
-  /**
-   * --aspects = a3, a2, a1: aspect a1 requires provider a1p, aspect a2 requires provider a2p and
-   * provides a1p and aspect a3 provides a2p. The three aspects will propagate together but aspect
-   * a1 will only see a1p and aspect a2 will only see a2p.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_stackOfAspects() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a2p = provider()",
-        "a1_result = provider()",
-        "a2_result = provider()",
-        "a3_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  if a2p in target:",
-        "    result += ' and sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' and cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  result = 'aspect a2 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  if a2p in target:",
-        "    result += ' and sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' and cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a2_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a2_result(value = complete_result), a1p(value = 'a1p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        "  required_aspect_providers = [a2p],",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  result = 'aspect a3 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  if a2p in target:",
-        "    result += ' and sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' and cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a3_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a3_result(value = complete_result), a2p(value = 'a2p_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a2p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a3 = getConfiguredAspect(configuredAspects, "a3");
-    assertThat(a3).isNotNull();
-    StarlarkProvider.Key a3Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a3_result");
-    StructImpl a3ResultProvider = (StructImpl) a3.get(a3Result);
-    assertThat((Sequence<?>) a3ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a3 on target //test:dep_target cannot see a1p and cannot see a2p",
-            "aspect a3 on target //test:main cannot see a1p and cannot see a2p");
-
-    ConfiguredAspect a2 = getConfiguredAspect(configuredAspects, "a2");
-    assertThat(a2).isNotNull();
-    StarlarkProvider.Key a2Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a2_result");
-    StructImpl a2ResultProvider = (StructImpl) a2.get(a2Result);
-    assertThat((Sequence<?>) a2ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a2 on target //test:dep_target cannot see a1p and sees a2p = a2p_val",
-            "aspect a2 on target //test:main cannot see a1p and sees a2p = a2p_val");
-
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a1p = a1p_val and cannot see a2p",
-            "aspect a1 on target //test:main sees a1p = a1p_val and cannot see a2p");
-  }
-
-  /**
-   * --aspects = a3, a2, a1: aspect a1 requires provider a1p, aspect a2 and aspect a3 provides a1p.
-   * This should fail because provider a1p is provided twice.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_requiredProviderProvidedTwiceFailed() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_a2_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_a3_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-    reporter.removeHandler(failFastHandler);
-
-    // The call to `update` does not throw an exception when "--keep_going" is passed in the
-    // WithKeepGoing test suite. Otherwise, it throws ViewCreationFailedException.
-    if (keepGoing()) {
-      AnalysisResult result =
-          update(
-              ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-              "//test:main");
-      assertThat(result.hasError()).isTrue();
-    } else {
-      assertThrows(
-          ViewCreationFailedException.class,
-          () ->
-              update(
-                  ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-                  "//test:main"));
-    }
-    assertContainsEvent("ERROR /workspace/test/BUILD:2:12: Provider a1p provided twice");
-  }
-
-  /**
-   * --aspects = a3, a1, a2: aspect a1 requires provider a1p, aspect a2 and aspect a3 provide a1p.
-   * a1 should see the value provided by a3 because a3 is listed before a1.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_requiredProviderProvidedTwicePassed() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_a2_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_a3_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a1", "test/defs.bzl%a2"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a1p = a1p_a3_val",
-            "aspect a1 on target //test:main sees a1p = a1p_a3_val");
-  }
-
-  @Test
-  public void testTopLevelAspectOnAspect_requiredProviderNotProvided() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a2p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a2p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(ImmutableList.of("test/defs.bzl%a2", "test/defs.bzl%a1"), "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target cannot see a1p",
-            "aspect a1 on target //test:main cannot see a1p");
-  }
-
-  /**
-   * --aspects = a1, a2: aspect a1 requires provider a1p, aspect a2 provides a1p but it was listed
-   * after a1 so aspect a1 cannot see a1p value.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_requiredProviderProvidedAfterTheAspect() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(ImmutableList.of("test/defs.bzl%a1", "test/defs.bzl%a2"), "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target cannot see a1p",
-            "aspect a1 on target //test:main cannot see a1p");
-  }
-
-  /**
-   * --aspects = a2, a1: aspect a1 requires provider a1p, aspect a2 provides a1p. But aspect a2
-   * propagates along different attr_aspects from a1 so a1 cannot get a1p on all dependency targets.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_differentAttrAspects() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result += ctx.rule.attr.dep[a1_result].value",
-        "  if ctx.rule.attr.extra_dep:",
-        "    complete_result += ctx.rule.attr.extra_dep[a1_result].value",
-        "  complete_result += [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep', 'extra_dep'],",
-        "  required_aspect_providers = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a1p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "    'extra_dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        "  extra_dep = ':extra_dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'extra_dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(ImmutableList.of("test/defs.bzl%a2", "test/defs.bzl%a1"), "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a1p = a1p_val",
-            "aspect a1 on target //test:extra_dep_target cannot see a1p",
-            "aspect a1 on target //test:main sees a1p = a1p_val");
-  }
-
-  /**
-   * --aspects = a2, a1: aspect a1 requires provider a1p, aspect a2 provides a1p. But aspect a2
-   * propagates along different required_providers from a1 so a1 cannot get a1p on all dependency
-   * targets.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_differentRequiredRuleProviders() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a1_result = provider()",
-        "rule_prov_a = provider()",
-        "rule_prov_b = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  complete_result = []",
-        "  if hasattr(ctx.rule.attr, 'deps'):",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result += dep[a1_result].value",
-        "  complete_result += [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [a1p],",
-        "  required_providers = [[rule_prov_a], [rule_prov_b]],",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a1p],",
-        "  required_providers = [rule_prov_a],",
-        ")",
-        "",
-        "def _main_rule_impl(ctx):",
-        "  return [rule_prov_a(), rule_prov_b()]",
-        "main_rule = rule(",
-        "  implementation = _main_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        ")",
-        "",
-        "def _rule_with_prov_a_impl(ctx):",
-        "  return [rule_prov_a()]",
-        "rule_with_prov_a = rule(",
-        "  implementation = _rule_with_prov_a_impl,",
-        "  provides = [rule_prov_a]",
-        ")",
-        "",
-        "def _rule_with_prov_b_impl(ctx):",
-        "  return [rule_prov_b()]",
-        "rule_with_prov_b = rule(",
-        "  implementation = _rule_with_prov_b_impl,",
-        "  provides = [rule_prov_b]",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'main_rule', 'rule_with_prov_a', 'rule_with_prov_b')",
-        "main_rule(",
-        "  name = 'main',",
-        "  deps = [':target_with_prov_a', ':target_with_prov_b'],",
-        ")",
-        "rule_with_prov_a(",
-        "  name = 'target_with_prov_a',",
-        ")",
-        "rule_with_prov_b(",
-        "  name = 'target_with_prov_b',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(ImmutableList.of("test/defs.bzl%a2", "test/defs.bzl%a1"), "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:target_with_prov_a sees a1p = a1p_val",
-            "aspect a1 on target //test:target_with_prov_b cannot see a1p",
-            "aspect a1 on target //test:main sees a1p = a1p_val");
-  }
-
-  /**
-   * --aspects = a3, a2, a1: both aspects a1 and a2 require provider a3p, aspect a3 provides a3p. a1
-   * and a2 should be able to read a3p.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_providerRequiredByMultipleAspects() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a3p = provider()",
-        "a1_result = provider()",
-        "a2_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a3p in target:",
-        "    result += ' sees a3p = {}'.format(target[a3p].value)",
-        "  else:",
-        "    result += ' cannot see a3p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a1_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a3p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  result = 'aspect a2 on target {}'.format(target.label)",
-        "  if a3p in target:",
-        "    result += ' sees a3p = {}'.format(target[a3p].value)",
-        "  else:",
-        "    result += ' cannot see a3p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.dep:",
-        "    complete_result = ctx.rule.attr.dep[a2_result].value + [result]",
-        "  else:",
-        "    complete_result = [result]",
-        "  return [a2_result(value = complete_result)]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['dep'],",
-        "  required_aspect_providers = [a3p]",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  return [a3p(value = 'a3p_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['dep'],",
-        "  provides = [a3p],",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'dep': attr.label(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  dep = ':dep_target',",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a2 = getConfiguredAspect(configuredAspects, "a2");
-    assertThat(a2).isNotNull();
-    StarlarkProvider.Key a2Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a2_result");
-    StructImpl a2ResultProvider = (StructImpl) a2.get(a2Result);
-    assertThat((Sequence<?>) a2ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a2 on target //test:dep_target sees a3p = a3p_val",
-            "aspect a2 on target //test:main sees a3p = a3p_val");
-
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a3p = a3p_val",
-            "aspect a1 on target //test:main sees a3p = a3p_val");
-  }
-
-  /**
-   * --aspects = a1, a2, a3: aspect a3 requires a1p and a2p, a1 provides a1p and a2 provides a2p.
-   *
-   * <p>top level target (main) has two dependencies t1 and t2. Aspects a1 and a3 can propagate to
-   * t1 and aspects a2 and a3 can propagate to t2. Both t1 and t2 have t0 as dependency, aspect a3
-   * will run twice on t0 once with aspects path (a1, a3) and the other with (a2, a3).
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_diamondCase() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a1p = provider()",
-        "a2p = provider()",
-        "a3_result = provider()",
-        "",
-        "r1p = provider()",
-        "r2p = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  return [a1p(value = 'a1p_val')]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_providers = [r1p],",
-        "  provides = [a1p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_providers = [r2p],",
-        "  provides = [a2p]",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  result = 'aspect a3 on target {}'.format(target.label)",
-        "  if a1p in target:",
-        "    result += ' sees a1p = {}'.format(target[a1p].value)",
-        "  else:",
-        "    result += ' cannot see a1p'",
-        "  if a2p in target:",
-        "    result += ' and sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' and cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a3_result].value)",
-        "  complete_result.append(result)",
-        "  return [a3_result(value = complete_result)]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [[a1p], [a2p]],",
-        ")",
-        "",
-        "def _r0_impl(ctx):",
-        "  return [r1p(), r2p()]",
-        "r0 = rule(",
-        "  implementation = _r0_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        "  provides = [r1p, r2p]",
-        ")",
-        "def _r1_impl(ctx):",
-        "  return [r1p()]",
-        "r1 = rule(",
-        "  implementation = _r1_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        "  provides = [r1p]",
-        ")",
-        "def _r2_impl(ctx):",
-        "  return [r2p()]",
-        "r2 = rule(",
-        "  implementation = _r2_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        "  provides = [r2p]",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'r0', 'r1', 'r2')",
-        "r0(",
-        "  name = 'main',",
-        "  deps = [':t1', ':t2'],",
-        ")",
-        "r1(",
-        "  name = 't1',",
-        "  deps = [':t0'],",
-        ")",
-        "r2(",
-        "  name = 't2',",
-        "  deps = [':t0'],",
-        ")",
-        "r0(",
-        "  name = 't0',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a1", "test/defs.bzl%a2", "test/defs.bzl%a3"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a3 = getConfiguredAspect(configuredAspects, "a3");
-    assertThat(a3).isNotNull();
-    StarlarkProvider.Key a3Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a3_result");
-    StructImpl a3ResultProvider = (StructImpl) a3.get(a3Result);
-    assertThat((Sequence<?>) a3ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a3 on target //test:t0 sees a1p = a1p_val and cannot see a2p",
-            "aspect a3 on target //test:t0 cannot see a1p and sees a2p = a2p_val",
-            "aspect a3 on target //test:t1 sees a1p = a1p_val and cannot see a2p",
-            "aspect a3 on target //test:t2 cannot see a1p and sees a2p = a2p_val",
-            "aspect a3 on target //test:main sees a1p = a1p_val and sees a2p = a2p_val");
-  }
-
-  @Test
-  public void testTopLevelAspectOnAspect_duplicateAspectsFailed() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a2p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a2p in target:",
-        "    result += ' sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a1_result].value)",
-        "  complete_result.append(result)",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [a2p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a2p]",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  deps = [':dep_target'],",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-    reporter.removeHandler(failFastHandler);
-
-    // The call to `update` does not throw an exception when "--keep_going" is passed in the
-    // WithKeepGoing test suite. Otherwise, it throws ViewCreationFailedException.
-    if (keepGoing()) {
-      AnalysisResult result =
-          update(
-              ImmutableList.of("test/defs.bzl%a1", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-              "//test:main");
-      assertThat(result.hasError()).isTrue();
-    } else {
-      assertThrows(
-          ViewCreationFailedException.class,
-          () ->
-              update(
-                  ImmutableList.of("test/defs.bzl%a1", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-                  "//test:main"));
-    }
-    assertContainsEvent("aspect //test:defs.bzl%a1 added more than once");
-  }
-
-  /**
-   * --aspects = a1 requires provider a2p provided by aspect a2. a1 is applied on top level target
-   * `main` whose rule propagates aspect a2 to its `deps`. So a1 on `main` cannot see a2p but it can
-   * see a2p on `main` deps.
-   */
-  @Test
-  public void testTopLevelAspectOnAspect_requiredAspectProviderOnlyAvailableOnDep()
-      throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a2p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a2p in target:",
-        "    result += ' sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a1_result].value)",
-        "  complete_result.append(result)",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [a2p]",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a2p]",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(aspects=[a2]),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  deps = [':dep_target'],",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult = update(ImmutableList.of("test/defs.bzl%a1"), "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a2p = a2p_val",
-            "aspect a1 on target //test:main cannot see a2p");
-  }
-
-  @Test
-  public void testTopLevelAspectOnAspect_multipleTopLevelTargets() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a2p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a2p in target:",
-        "    result += ' sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' cannot see a2p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a1_result].value)",
-        "  complete_result.append(result)",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [a2p],",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a2p]",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 't1',",
-        ")",
-        "simple_rule(",
-        "  name = 't2',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(ImmutableList.of("test/defs.bzl%a2", "test/defs.bzl%a1"), "//test:t2", "//test:t1");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1Ont1 = getConfiguredAspect(configuredAspects, "a1", "t1");
-    assertThat(a1Ont1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1Ont1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly("aspect a1 on target //test:t1 sees a2p = a2p_val");
-
-    ConfiguredAspect a1Ont2 = getConfiguredAspect(configuredAspects, "a1", "t2");
-    assertThat(a1Ont2).isNotNull();
-    a1ResultProvider = (StructImpl) a1Ont2.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly("aspect a1 on target //test:t2 sees a2p = a2p_val");
-  }
-
-  @Test
-  public void testTopLevelAspectOnAspect_multipleRequiredProviders() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a2p = provider()",
-        "a3p = provider()",
-        "a1_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a2p in target:",
-        "    result += ' sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' cannot see a2p'",
-        "  if a3p in target:",
-        "    result += ' and sees a3p = {}'.format(target[a3p].value)",
-        "  else:",
-        "    result += ' and cannot see a3p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a1_result].value)",
-        "  complete_result.append(result)",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [[a2p], [a3p]],",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  return [a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a2p]",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  return [a3p(value = 'a3p_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a3p]",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  deps = [':dep_target'],",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a2p = a2p_val and sees a3p = a3p_val",
-            "aspect a1 on target //test:main sees a2p = a2p_val and sees a3p = a3p_val");
-  }
-
-  @Test
-  public void testTopLevelAspectOnAspect_multipleRequiredProviders2() throws Exception {
-    scratch.file(
-        "test/defs.bzl",
-        "a2p = provider()",
-        "a3p = provider()",
-        "a1_result = provider()",
-        "a2_result = provider()",
-        "",
-        "def _a1_impl(target, ctx):",
-        "  result = 'aspect a1 on target {}'.format(target.label)",
-        "  if a2p in target:",
-        "    result += ' sees a2p = {}'.format(target[a2p].value)",
-        "  else:",
-        "    result += ' cannot see a2p'",
-        "  if a3p in target:",
-        "    result += ' and sees a3p = {}'.format(target[a3p].value)",
-        "  else:",
-        "    result += ' and cannot see a3p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a1_result].value)",
-        "  complete_result.append(result)",
-        "  return [a1_result(value = complete_result)]",
-        "a1 = aspect(",
-        "  implementation = _a1_impl,",
-        "  attr_aspects = ['deps'],",
-        "  required_aspect_providers = [[a2p], [a3p]],",
-        ")",
-        "",
-        "def _a2_impl(target, ctx):",
-        "  result = 'aspect a2 on target {}'.format(target.label)",
-        "  if a3p in target:",
-        "    result += ' sees a3p = {}'.format(target[a3p].value)",
-        "  else:",
-        "    result += ' cannot see a3p'",
-        "  complete_result = []",
-        "  if ctx.rule.attr.deps:",
-        "    for dep in ctx.rule.attr.deps:",
-        "      complete_result.extend(dep[a2_result].value)",
-        "  complete_result.append(result)",
-        "  return [a2_result(value = complete_result), a2p(value = 'a2p_val')]",
-        "a2 = aspect(",
-        "  implementation = _a2_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a2p],",
-        "  required_aspect_providers = [a3p]",
-        ")",
-        "",
-        "def _a3_impl(target, ctx):",
-        "  return [a3p(value = 'a3p_val')]",
-        "a3 = aspect(",
-        "  implementation = _a3_impl,",
-        "  attr_aspects = ['deps'],",
-        "  provides = [a3p]",
-        ")",
-        "",
-        "def _simple_rule_impl(ctx):",
-        "  pass",
-        "simple_rule = rule(",
-        "  implementation = _simple_rule_impl,",
-        "  attrs = {",
-        "    'deps': attr.label_list(),",
-        "  },",
-        ")");
-    scratch.file(
-        "test/BUILD",
-        "load('//test:defs.bzl', 'simple_rule')",
-        "simple_rule(",
-        "  name = 'main',",
-        "  deps = [':dep_target'],",
-        ")",
-        "simple_rule(",
-        "  name = 'dep_target',",
-        ")");
-
-    AnalysisResult analysisResult =
-        update(
-            ImmutableList.of("test/defs.bzl%a3", "test/defs.bzl%a2", "test/defs.bzl%a1"),
-            "//test:main");
-
-    Map<AspectKey, ConfiguredAspect> configuredAspects = analysisResult.getAspectsMap();
-    ConfiguredAspect a1 = getConfiguredAspect(configuredAspects, "a1");
-    assertThat(a1).isNotNull();
-    StarlarkProvider.Key a1Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a1_result");
-    StructImpl a1ResultProvider = (StructImpl) a1.get(a1Result);
-    assertThat((Sequence<?>) a1ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a1 on target //test:dep_target sees a2p = a2p_val and sees a3p = a3p_val",
-            "aspect a1 on target //test:main sees a2p = a2p_val and sees a3p = a3p_val");
-
-    ConfiguredAspect a2 = getConfiguredAspect(configuredAspects, "a2");
-    assertThat(a2).isNotNull();
-    StarlarkProvider.Key a2Result =
-        new StarlarkProvider.Key(
-            Label.parseAbsolute("//test:defs.bzl", ImmutableMap.of()), "a2_result");
-    StructImpl a2ResultProvider = (StructImpl) a2.get(a2Result);
-    assertThat((Sequence<?>) a2ResultProvider.getValue("value"))
-        .containsExactly(
-            "aspect a2 on target //test:dep_target sees a3p = a3p_val",
-            "aspect a2 on target //test:main sees a3p = a3p_val");
-  }
-
-  private ConfiguredAspect getConfiguredAspect(
-      Map<AspectKey, ConfiguredAspect> aspectsMap, String aspectName) {
-    for (Map.Entry<AspectKey, ConfiguredAspect> entry : aspectsMap.entrySet()) {
-      String aspectExportedName =
-          ((StarlarkAspectClass) entry.getKey().getAspectClass()).getExportedName();
-      if (aspectExportedName.equals(aspectName)) {
-        return entry.getValue();
-      }
-    }
-    return null;
-  }
-
-  private ConfiguredAspect getConfiguredAspect(
-      Map<AspectKey, ConfiguredAspect> aspectsMap, String aspectName, String targetName) {
-    for (Map.Entry<AspectKey, ConfiguredAspect> entry : aspectsMap.entrySet()) {
-      String aspectExportedName =
-          ((StarlarkAspectClass) entry.getKey().getAspectClass()).getExportedName();
-      String target = entry.getKey().getLabel().getName();
-      if (aspectExportedName.equals(aspectName) && target.equals(targetName)) {
-        return entry.getValue();
-      }
-    }
-    return null;
-  }
-
   /** StarlarkAspectTest with "keep going" flag */
   @RunWith(JUnit4.class)
   public static final class WithKeepGoing extends StarlarkDefinedAspectsTest {