Restrict aspects visible to other aspects according to their advertised providers.

--
PiperOrigin-RevId: 147526961
MOS_MIGRATED_REVID=147526961
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java b/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java
index 25477bd..0714a0d 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/AspectValueTest.java
@@ -13,6 +13,7 @@
 // limitations under the License.
 package com.google.devtools.build.lib.analysis;
 
+import com.google.common.collect.ImmutableList;
 import com.google.common.testing.EqualsTester;
 import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
 import com.google.devtools.build.lib.analysis.util.AnalysisTestCase;
@@ -234,7 +235,8 @@
     AspectKey baseKey = AspectValue.createAspectKey(label, baseConfiguration,
         new AspectDescriptor(aspectClass1, parameters1), aspectConfiguration1);
     return ActionLookupValue.key(AspectValue.createAspectKey(
-        baseKey, new AspectDescriptor(aspectClass2, parameters2),
+        label, baseConfiguration,
+        ImmutableList.of(baseKey), new AspectDescriptor(aspectClass2, parameters2),
         aspectConfiguration2
     ));
   }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
index d7be1ff..28ce907 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/BuildViewTest.java
@@ -27,7 +27,6 @@
 
 import com.google.common.base.Function;
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
@@ -44,7 +43,6 @@
 import com.google.devtools.build.lib.analysis.util.BuildViewTestBase;
 import com.google.devtools.build.lib.analysis.util.ExpectedDynamicConfigurationErrors;
 import com.google.devtools.build.lib.cmdline.Label;
-import com.google.devtools.build.lib.packages.AspectDescriptor;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.skyframe.SkyFunctions;
@@ -371,7 +369,7 @@
           Dependency.withTransitionAndAspects(
               Label.parseAbsolute("//package:inner"),
               Attribute.ConfigurationTransition.NONE,
-              ImmutableSet.<AspectDescriptor>of());
+              AspectCollection.EMPTY);
     } else {
       innerDependency =
           Dependency.withConfiguration(
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java b/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java
index eb6b551..09a2c17 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/DependencyResolverTest.java
@@ -135,7 +135,7 @@
     }
 
     assertNotNull("Dependency '" + dep + "' on attribute '" + attrName + "' not found", dependency);
-    assertThat(dependency.getAspects()).containsExactly((Object[]) aspects);
+    assertThat(dependency.getAspects().getAllAspects()).containsExactly((Object[]) aspects);
     return dependency;
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/DependencyTest.java b/src/test/java/com/google/devtools/build/lib/analysis/DependencyTest.java
index 82e1472..03369f7 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/DependencyTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/DependencyTest.java
@@ -26,8 +26,6 @@
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.packages.AspectDescriptor;
 import com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition;
-import java.util.LinkedHashSet;
-import java.util.Set;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
@@ -46,8 +44,7 @@
     assertThat(nullDep.getLabel()).isEqualTo(Label.parseAbsolute("//a"));
     assertThat(nullDep.hasStaticConfiguration()).isTrue();
     assertThat(nullDep.getConfiguration()).isNull();
-    assertThat(nullDep.getAspects()).isEmpty();
-    assertThat(nullDep.getAspectConfigurations()).isEmpty();
+    assertThat(nullDep.getAspects().getAllAspects()).isEmpty();
 
     try {
       nullDep.getTransition();
@@ -66,8 +63,7 @@
     assertThat(targetDep.getLabel()).isEqualTo(Label.parseAbsolute("//a"));
     assertThat(targetDep.hasStaticConfiguration()).isTrue();
     assertThat(targetDep.getConfiguration()).isEqualTo(getTargetConfiguration());
-    assertThat(targetDep.getAspects()).isEmpty();
-    assertThat(targetDep.getAspectConfigurations()).isEmpty();
+    assertThat(targetDep.getAspects().getAllAspects()).isEmpty();
 
     try {
       targetDep.getTransition();
@@ -82,7 +78,8 @@
     update();
     AspectDescriptor simpleAspect = new AspectDescriptor(TestAspects.SIMPLE_ASPECT);
     AspectDescriptor attributeAspect = new AspectDescriptor(TestAspects.ATTRIBUTE_ASPECT);
-    ImmutableSet<AspectDescriptor> twoAspects = ImmutableSet.of(simpleAspect, attributeAspect);
+    AspectCollection twoAspects = AspectCollection.createForTests(
+        ImmutableSet.of(simpleAspect, attributeAspect));
     Dependency targetDep =
         Dependency.withConfigurationAndAspects(
             Label.parseAbsolute("//a"), getTargetConfiguration(), twoAspects);
@@ -90,12 +87,10 @@
     assertThat(targetDep.getLabel()).isEqualTo(Label.parseAbsolute("//a"));
     assertThat(targetDep.hasStaticConfiguration()).isTrue();
     assertThat(targetDep.getConfiguration()).isEqualTo(getTargetConfiguration());
-    assertThat(targetDep.getAspects()).containsExactlyElementsIn(twoAspects);
-    assertThat(targetDep.getAspectConfigurations())
-        .containsExactlyEntriesIn(
-            ImmutableMap.of(
-                simpleAspect, getTargetConfiguration(),
-                attributeAspect, getTargetConfiguration()));
+    assertThat(targetDep.getAspects()).isEqualTo(twoAspects);
+    assertThat(targetDep.getAspectConfiguration(simpleAspect)).isEqualTo(getTargetConfiguration());
+    assertThat(targetDep.getAspectConfiguration(attributeAspect))
+        .isEqualTo(getTargetConfiguration());
 
     try {
       targetDep.getTransition();
@@ -106,27 +101,12 @@
   }
 
   @Test
-  public void withConfigurationAndAspects_RejectsNullAspectsWithNPE() throws Exception {
-    update();
-    Set<AspectDescriptor> nullSet = new LinkedHashSet<>();
-    nullSet.add(null);
-
-    try {
-      Dependency.withConfigurationAndAspects(
-          Label.parseAbsolute("//a"), getTargetConfiguration(), nullSet);
-      fail("should not be allowed to create a dependency with a null aspect");
-    } catch (NullPointerException expected) {
-      // good. just as planned.
-    }
-  }
-
-  @Test
   public void withConfigurationAndAspects_RejectsNullConfigWithNPE() throws Exception {
     // Although the NullPointerTester should check this, this test invokes a different code path,
     // because it includes aspects (which the NPT test will not).
     AspectDescriptor simpleAspect = new AspectDescriptor(TestAspects.SIMPLE_ASPECT);
     AspectDescriptor attributeAspect = new AspectDescriptor(TestAspects.ATTRIBUTE_ASPECT);
-    ImmutableSet<AspectDescriptor> twoAspects = ImmutableSet.of(simpleAspect, attributeAspect);
+    AspectCollection twoAspects = AspectCollection.createForTests(simpleAspect, attributeAspect);
 
     try {
       Dependency.withConfigurationAndAspects(Label.parseAbsolute("//a"), null, twoAspects);
@@ -143,10 +123,9 @@
         Dependency.withConfigurationAndAspects(
             Label.parseAbsolute("//a"),
             getTargetConfiguration(),
-            ImmutableSet.<AspectDescriptor>of());
+            AspectCollection.EMPTY);
     // Here we're also checking that this doesn't throw an exception. No boom? OK. Good.
-    assertThat(dep.getAspects()).isEmpty();
-    assertThat(dep.getAspectConfigurations()).isEmpty();
+    assertThat(dep.getAspects().getAllAspects()).isEmpty();
   }
 
   @Test
@@ -154,18 +133,22 @@
     update();
     AspectDescriptor simpleAspect = new AspectDescriptor(TestAspects.SIMPLE_ASPECT);
     AspectDescriptor attributeAspect = new AspectDescriptor(TestAspects.ATTRIBUTE_ASPECT);
+    AspectCollection aspects =
+        AspectCollection.createForTests(ImmutableSet.of(simpleAspect, attributeAspect));
     ImmutableMap<AspectDescriptor, BuildConfiguration> twoAspectMap = ImmutableMap.of(
         simpleAspect, getTargetConfiguration(), attributeAspect, getHostConfiguration());
     Dependency targetDep =
         Dependency.withConfiguredAspects(
-            Label.parseAbsolute("//a"), getTargetConfiguration(), twoAspectMap);
+            Label.parseAbsolute("//a"), getTargetConfiguration(), aspects, twoAspectMap);
 
     assertThat(targetDep.getLabel()).isEqualTo(Label.parseAbsolute("//a"));
     assertThat(targetDep.hasStaticConfiguration()).isTrue();
     assertThat(targetDep.getConfiguration()).isEqualTo(getTargetConfiguration());
-    assertThat(targetDep.getAspects())
+    assertThat(targetDep.getAspects().getAllAspects())
         .containsExactlyElementsIn(ImmutableSet.of(simpleAspect, attributeAspect));
-    assertThat(targetDep.getAspectConfigurations()).containsExactlyEntriesIn(twoAspectMap);
+    assertThat(targetDep.getAspectConfiguration(simpleAspect)).isEqualTo(getTargetConfiguration());
+    assertThat(targetDep.getAspectConfiguration(attributeAspect))
+        .isEqualTo(getHostConfiguration());
 
     try {
       targetDep.getTransition();
@@ -182,24 +165,26 @@
     Dependency dep =
         Dependency.withConfiguredAspects(
             Label.parseAbsolute("//a"), getTargetConfiguration(),
+            AspectCollection.EMPTY,
             ImmutableMap.<AspectDescriptor, BuildConfiguration>of());
     // Here we're also checking that this doesn't throw an exception. No boom? OK. Good.
-    assertThat(dep.getAspects()).isEmpty();
-    assertThat(dep.getAspectConfigurations()).isEmpty();
+    assertThat(dep.getAspects().getAllAspects()).isEmpty();
   }
 
   @Test
   public void withTransitionAndAspects_BasicAccessors() throws Exception {
     AspectDescriptor simpleAspect = new AspectDescriptor(TestAspects.SIMPLE_ASPECT);
     AspectDescriptor attributeAspect = new AspectDescriptor(TestAspects.ATTRIBUTE_ASPECT);
-    ImmutableSet<AspectDescriptor> twoAspects = ImmutableSet.of(simpleAspect, attributeAspect);
+    AspectCollection twoAspects = AspectCollection.createForTests(
+        ImmutableSet.of(simpleAspect, attributeAspect));
     Dependency hostDep =
         Dependency.withTransitionAndAspects(
             Label.parseAbsolute("//a"), ConfigurationTransition.HOST, twoAspects);
 
     assertThat(hostDep.getLabel()).isEqualTo(Label.parseAbsolute("//a"));
     assertThat(hostDep.hasStaticConfiguration()).isFalse();
-    assertThat(hostDep.getAspects()).containsExactlyElementsIn(twoAspects);
+    assertThat(hostDep.getAspects().getAllAspects())
+        .containsExactlyElementsIn(twoAspects.getAllAspects());
     assertThat(hostDep.getTransition()).isEqualTo(ConfigurationTransition.HOST);
 
     try {
@@ -210,9 +195,17 @@
     }
 
     try {
-      hostDep.getAspectConfigurations();
+      hostDep.getAspectConfiguration(simpleAspect);
       fail("withTransitionAndAspects-created Dependencies should throw ISE on "
-          + "getAspectConfigurations()");
+          + "getAspectConfiguration()");
+    } catch (IllegalStateException ex) {
+      // good. you're so predictable.
+    }
+
+    try {
+      hostDep.getAspectConfiguration(attributeAspect);
+      fail("withTransitionAndAspects-created Dependencies should throw ISE on "
+          + "getAspectConfiguration()");
     } catch (IllegalStateException ex) {
       // good. you're so predictable.
     }
@@ -224,9 +217,9 @@
     Dependency dep =
         Dependency.withTransitionAndAspects(
             Label.parseAbsolute("//a"), ConfigurationTransition.HOST,
-            ImmutableSet.<AspectDescriptor>of());
+            AspectCollection.EMPTY);
     // Here we're also checking that this doesn't throw an exception. No boom? OK. Good.
-    assertThat(dep.getAspects()).isEmpty();
+    assertThat(dep.getAspects().getAllAspects()).isEmpty();
   }
 
   @Test
@@ -254,10 +247,13 @@
     AspectDescriptor attributeAspect = new AspectDescriptor(TestAspects.ATTRIBUTE_ASPECT);
     AspectDescriptor errorAspect = new AspectDescriptor(TestAspects.ERROR_ASPECT);
 
-    ImmutableSet<AspectDescriptor> twoAspects = ImmutableSet.of(simpleAspect, attributeAspect);
-    ImmutableSet<AspectDescriptor> inverseAspects = ImmutableSet.of(attributeAspect, simpleAspect);
-    ImmutableSet<AspectDescriptor> differentAspects = ImmutableSet.of(attributeAspect, errorAspect);
-    ImmutableSet<AspectDescriptor> noAspects = ImmutableSet.<AspectDescriptor>of();
+    AspectCollection twoAspects =
+        AspectCollection.createForTests(simpleAspect, attributeAspect);
+    AspectCollection inverseAspects =
+        AspectCollection.createForTests(attributeAspect, simpleAspect);
+    AspectCollection differentAspects =
+        AspectCollection.createForTests(attributeAspect, errorAspect);
+    AspectCollection noAspects = AspectCollection.EMPTY;
 
     ImmutableMap<AspectDescriptor, BuildConfiguration> twoAspectsHostMap =
         ImmutableMap.of(simpleAspect, host, attributeAspect, host);
@@ -277,21 +273,21 @@
             Dependency.withConfigurationAndAspects(aExplicit, host, twoAspects),
             Dependency.withConfigurationAndAspects(a, host, inverseAspects),
             Dependency.withConfigurationAndAspects(aExplicit, host, inverseAspects),
-            Dependency.withConfiguredAspects(a, host, twoAspectsHostMap),
-            Dependency.withConfiguredAspects(aExplicit, host, twoAspectsHostMap))
+            Dependency.withConfiguredAspects(a, host, twoAspects, twoAspectsHostMap),
+            Dependency.withConfiguredAspects(aExplicit, host, twoAspects, twoAspectsHostMap))
         .addEqualityGroup(
             // base set but with label //b
             Dependency.withConfigurationAndAspects(b, host, twoAspects),
             Dependency.withConfigurationAndAspects(b, host, inverseAspects),
-            Dependency.withConfiguredAspects(b, host, twoAspectsHostMap))
+            Dependency.withConfiguredAspects(b, host, twoAspects, twoAspectsHostMap))
         .addEqualityGroup(
             // base set but with target configuration
             Dependency.withConfigurationAndAspects(a, target, twoAspects),
             Dependency.withConfigurationAndAspects(aExplicit, target, twoAspects),
             Dependency.withConfigurationAndAspects(a, target, inverseAspects),
             Dependency.withConfigurationAndAspects(aExplicit, target, inverseAspects),
-            Dependency.withConfiguredAspects(a, target, twoAspectsTargetMap),
-            Dependency.withConfiguredAspects(aExplicit, target, twoAspectsTargetMap))
+            Dependency.withConfiguredAspects(a, target, twoAspects, twoAspectsTargetMap),
+            Dependency.withConfiguredAspects(aExplicit, target, twoAspects, twoAspectsTargetMap))
         .addEqualityGroup(
             // base set but with null configuration
             Dependency.withNullConfiguration(a),
@@ -300,56 +296,63 @@
             // base set but with different aspects
             Dependency.withConfigurationAndAspects(a, host, differentAspects),
             Dependency.withConfigurationAndAspects(aExplicit, host, differentAspects),
-            Dependency.withConfiguredAspects(a, host, differentAspectsHostMap),
-            Dependency.withConfiguredAspects(aExplicit, host, differentAspectsHostMap))
+            Dependency.withConfiguredAspects(
+                a, host, differentAspects, differentAspectsHostMap),
+            Dependency.withConfiguredAspects(
+                aExplicit, host, differentAspects, differentAspectsHostMap))
         .addEqualityGroup(
             // base set but with label //b and target configuration
             Dependency.withConfigurationAndAspects(b, target, twoAspects),
             Dependency.withConfigurationAndAspects(b, target, inverseAspects),
-            Dependency.withConfiguredAspects(b, target, twoAspectsTargetMap))
+            Dependency.withConfiguredAspects(b, target,
+                twoAspects, twoAspectsTargetMap))
         .addEqualityGroup(
             // base set but with label //b and null configuration
             Dependency.withNullConfiguration(b))
         .addEqualityGroup(
             // base set but with label //b and different aspects
             Dependency.withConfigurationAndAspects(b, host, differentAspects),
-            Dependency.withConfiguredAspects(b, host, differentAspectsHostMap))
+            Dependency.withConfiguredAspects(
+                b, host, differentAspects, differentAspectsHostMap))
         .addEqualityGroup(
             // base set but with target configuration and different aspects
             Dependency.withConfigurationAndAspects(a, target, differentAspects),
             Dependency.withConfigurationAndAspects(aExplicit, target, differentAspects),
-            Dependency.withConfiguredAspects(a, target, differentAspectsTargetMap),
-            Dependency.withConfiguredAspects(aExplicit, target, differentAspectsTargetMap))
+            Dependency.withConfiguredAspects(
+                a, target, differentAspects, differentAspectsTargetMap),
+            Dependency.withConfiguredAspects(
+                aExplicit, target, differentAspects, differentAspectsTargetMap))
         .addEqualityGroup(
             // inverse of base set: //b, target configuration, different aspects
             Dependency.withConfigurationAndAspects(b, target, differentAspects),
-            Dependency.withConfiguredAspects(b, target, differentAspectsTargetMap))
+            Dependency.withConfiguredAspects(
+                b, target, differentAspects, differentAspectsTargetMap))
         .addEqualityGroup(
             // base set but with no aspects
             Dependency.withConfiguration(a, host),
             Dependency.withConfiguration(aExplicit, host),
             Dependency.withConfigurationAndAspects(a, host, noAspects),
             Dependency.withConfigurationAndAspects(aExplicit, host, noAspects),
-            Dependency.withConfiguredAspects(a, host, noAspectsMap),
-            Dependency.withConfiguredAspects(aExplicit, host, noAspectsMap))
+            Dependency.withConfiguredAspects(a, host, noAspects, noAspectsMap),
+            Dependency.withConfiguredAspects(aExplicit, host, noAspects, noAspectsMap))
         .addEqualityGroup(
             // base set but with label //b and no aspects
             Dependency.withConfiguration(b, host),
             Dependency.withConfigurationAndAspects(b, host, noAspects),
-            Dependency.withConfiguredAspects(b, host, noAspectsMap))
+            Dependency.withConfiguredAspects(b, host, noAspects, noAspectsMap))
         .addEqualityGroup(
             // base set but with target configuration and no aspects
             Dependency.withConfiguration(a, target),
             Dependency.withConfiguration(aExplicit, target),
             Dependency.withConfigurationAndAspects(a, target, noAspects),
             Dependency.withConfigurationAndAspects(aExplicit, target, noAspects),
-            Dependency.withConfiguredAspects(a, target, noAspectsMap),
-            Dependency.withConfiguredAspects(aExplicit, target, noAspectsMap))
+            Dependency.withConfiguredAspects(a, target, noAspects, noAspectsMap),
+            Dependency.withConfiguredAspects(aExplicit, target, noAspects, noAspectsMap))
         .addEqualityGroup(
             // inverse of base set: //b, target configuration, no aspects
             Dependency.withConfiguration(b, target),
             Dependency.withConfigurationAndAspects(b, target, noAspects),
-            Dependency.withConfiguredAspects(b, target, noAspectsMap))
+            Dependency.withConfiguredAspects(b, target, noAspects, noAspectsMap))
         .addEqualityGroup(
             // base set but with transition HOST
             Dependency.withTransitionAndAspects(a, ConfigurationTransition.HOST, twoAspects),
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
index 44eff26..4ba7fb8 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkAspectsTest.java
@@ -1464,7 +1464,7 @@
         "a1p = provider()",
         "def _a1_impl(target,ctx):",
         "  return struct(a1p = a1p(text = 'random'))",
-        "a1 = aspect(_a1_impl, attr_aspects = ['dep'])",
+        "a1 = aspect(_a1_impl, attr_aspects = ['dep'], provides = ['a1p'])",
         "a2p = provider()",
         "def _a2_impl(target,ctx):",
         "  value = []",
@@ -1475,7 +1475,7 @@
         "  else:",
         "     value.append(str(target.label) + str(target.aspect_ids) + '=no')",
         "  return struct(a2p = a2p(value = value))",
-        "a2 = aspect(_a2_impl, attr_aspects = ['dep'])",
+        "a2 = aspect(_a2_impl, attr_aspects = ['dep'], required_aspect_providers = ['a1p'])",
         "def _r1_impl(ctx):",
         "  pass",
         "def _r2_impl(ctx):",
@@ -1499,7 +1499,6 @@
         "//test:r0[\"//test:aspect.bzl%a1\"]=yes",
         "//test:r1[]=no");
   }
-
   /**
    * Diamond case.
    * rule r1 depends or r0 with aspect a1.
@@ -1515,11 +1514,11 @@
         "test/aspect.bzl",
         "def _a1_impl(target,ctx):",
         "  return struct(a1p = 'text from a1')",
-        "a1 = aspect(_a1_impl, attr_aspects = ['deps'])",
+        "a1 = aspect(_a1_impl, attr_aspects = ['deps'], provides = ['a1p'])",
         "",
         "def _a2_impl(target,ctx):",
         "  return struct(a2p = 'text from a2')",
-        "a2 = aspect(_a2_impl, attr_aspects = ['deps'])",
+        "a2 = aspect(_a2_impl, attr_aspects = ['deps'], provides = ['a2p'])",
         "",
         "def _a3_impl(target,ctx):",
         "  value = []",
@@ -1535,7 +1534,8 @@
         "     s += 'a2p'",
         "  value.append(s)",
         "  return struct(a3p = value)",
-        "a3 = aspect(_a3_impl, attr_aspects = ['deps'])",
+        "a3 = aspect(_a3_impl, attr_aspects = ['deps'],",
+        "            required_aspect_providers = [['a1p'], ['a2p']])",
         "def _r1_impl(ctx):",
         "  pass",
         "def _rcollect_impl(ctx):",
@@ -1572,6 +1572,7 @@
    * r1 depends on r2_1 with aspect a1.
    * r2 depends on r1 with aspect a2.
    *
+   * a2 is not interested in a1.
    * There should be just one instance of aspect a2 on r0, and is should *not* see a1.
    */
   @Test
@@ -1581,7 +1582,7 @@
         "a1p = provider()",
         "def _a1_impl(target,ctx):",
         "  return struct(a1p = 'a1p')",
-        "a1 = aspect(_a1_impl, attr_aspects = ['dep'])",
+        "a1 = aspect(_a1_impl, attr_aspects = ['dep'], provides = ['a1p'])",
         "a2p = provider()",
         "def _a2_impl(target,ctx):",
         "  value = []",
@@ -1592,7 +1593,7 @@
         "  else:",
         "     value.append(str(target.label) + str(target.aspect_ids) + '=no')",
         "  return struct(a2p = a2p(value = value))",
-        "a2 = aspect(_a2_impl, attr_aspects = ['dep'])",
+        "a2 = aspect(_a2_impl, attr_aspects = ['dep'], required_aspect_providers = [])",
         "def _r1_impl(ctx):",
         "  pass",
         "def _r2_impl(ctx):",
@@ -1614,7 +1615,7 @@
     // "yes" means that aspect a2 sees a1's providers.
     assertThat(result).containsExactly("//test:r0[]=no",
         "//test:r1[]=no",
-        "//test:r2_1[\"//test:aspect.bzl%a1\"]=yes");
+        "//test:r2_1[]=no");
   }
 
   /**
@@ -1627,7 +1628,7 @@
         "a1p = provider()",
         "def _a1_impl(target,ctx):",
         "  return struct(a1p = a1p(text = 'random'))",
-        "a1 = aspect(_a1_impl, attr_aspects = ['dep'])",
+        "a1 = aspect(_a1_impl, attr_aspects = ['dep'], provides = ['a1p'])",
         "a2p = provider()",
         "def _a2_impl(target,ctx):",
         "  value = []",
@@ -1638,7 +1639,7 @@
         "  else:",
         "     value.append(str(target.label) + str(target.aspect_ids) + '=no')",
         "  return struct(a2p = a2p(value = value))",
-        "a2 = aspect(_a2_impl, attr_aspects = ['dep'])",
+        "a2 = aspect(_a2_impl, attr_aspects = ['dep'], required_aspect_providers = ['a1p'])",
         "def _r1_impl(ctx):",
         "  pass",
         "def _r2_impl(ctx):",
@@ -1664,10 +1665,6 @@
         "//test:r1[]=no");
   }
 
-
-  /**
-   * Linear aspects-on-aspects with alias rule.
-   */
   @Test
   public void aspectDescriptions() throws Exception {
     scratch.file(