Report inconsistent aspect order error to the user.
--
PiperOrigin-RevId: 148342788
MOS_MIGRATED_REVID=148342788
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 015fea9..77cefb5 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
@@ -35,6 +35,7 @@
import com.google.devtools.build.lib.actions.ArtifactFactory;
import com.google.devtools.build.lib.actions.ArtifactOwner;
import com.google.devtools.build.lib.actions.Root;
+import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfigurationCollection;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -962,7 +963,8 @@
@VisibleForTesting
public Iterable<ConfiguredTarget> getDirectPrerequisitesForTesting(
EventHandler eventHandler, ConfiguredTarget ct, BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException,
+ InterruptedException, InconsistentAspectOrderException {
return skyframeExecutor.getConfiguredTargets(
eventHandler, ct.getConfiguration(),
ImmutableSet.copyOf(
@@ -974,7 +976,8 @@
public OrderedSetMultimap<Attribute, Dependency> getDirectPrerequisiteDependenciesForTesting(
final EventHandler eventHandler, final ConfiguredTarget ct,
BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
if (!(ct.getTarget() instanceof Rule)) {
return OrderedSetMultimap.create();
}
@@ -1062,7 +1065,8 @@
private OrderedSetMultimap<Attribute, ConfiguredTarget> getPrerequisiteMapForTesting(
final EventHandler eventHandler, ConfiguredTarget target,
BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException,
+ InterruptedException, InconsistentAspectOrderException {
OrderedSetMultimap<Attribute, Dependency> depNodeNames =
getDirectPrerequisiteDependenciesForTesting(eventHandler, target, configurations);
@@ -1094,7 +1098,8 @@
public RuleContext getRuleContextForTesting(
ConfiguredTarget target, StoredEventHandler eventHandler,
BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
BuildConfiguration targetConfig = target.getConfiguration();
CachingAnalysisEnvironment env =
new CachingAnalysisEnvironment(getArtifactFactory(),
@@ -1111,7 +1116,8 @@
@VisibleForTesting
public RuleContext getRuleContextForTesting(EventHandler eventHandler, ConfiguredTarget target,
AnalysisEnvironment env, BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
BuildConfiguration targetConfig = target.getConfiguration();
return new RuleContext.Builder(
env,
@@ -1139,7 +1145,8 @@
public ConfiguredTarget getPrerequisiteConfiguredTargetForTesting(
EventHandler eventHandler, ConfiguredTarget dependentTarget, Label desiredTarget,
BuildConfigurationCollection configurations)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
Collection<ConfiguredTarget> configuredTargets =
getPrerequisiteMapForTesting(eventHandler, dependentTarget, configurations).values();
for (ConfiguredTarget ct : configuredTargets) {
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
index 06d561b..440e7b5 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/DependencyResolver.java
@@ -26,6 +26,7 @@
import com.google.devtools.build.lib.analysis.config.PatchTransition;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.events.Location;
import com.google.devtools.build.lib.packages.Aspect;
import com.google.devtools.build.lib.packages.AspectClass;
import com.google.devtools.build.lib.packages.AspectDescriptor;
@@ -91,7 +92,8 @@
BuildConfiguration hostConfig,
@Nullable Aspect aspect,
ImmutableMap<Label, ConfigMatchingProvider> configConditions)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
NestedSetBuilder<Label> rootCauses = NestedSetBuilder.<Label>stableOrder();
OrderedSetMultimap<Attribute, Dependency> outgoingEdges = dependentNodeMap(
node, hostConfig,
@@ -138,7 +140,8 @@
Iterable<Aspect> aspects,
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
NestedSetBuilder<Label> rootCauses)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InterruptedException,
+ InconsistentAspectOrderException {
Target target = node.getTarget();
BuildConfiguration config = node.getConfiguration();
OrderedSetMultimap<Attribute, Dependency> outgoingEdges = OrderedSetMultimap.create();
@@ -158,6 +161,7 @@
} else {
throw new IllegalStateException(target.getLabel().toString());
}
+
return outgoingEdges;
}
@@ -168,7 +172,8 @@
ImmutableMap<Label, ConfigMatchingProvider> configConditions,
NestedSetBuilder<Label> rootCauses,
OrderedSetMultimap<Attribute, Dependency> outgoingEdges)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException,
+ InterruptedException{
Preconditions.checkArgument(node.getTarget() instanceof Rule);
BuildConfiguration ruleConfig = Preconditions.checkNotNull(node.getConfiguration());
Rule rule = (Rule) node.getTarget();
@@ -188,7 +193,7 @@
* (which require special processing: see {@link #resolveLateBoundAttributes}).
*/
private void resolveEarlyBoundAttributes(RuleResolver depResolver)
- throws EvalException, InterruptedException {
+ throws EvalException, InterruptedException, InconsistentAspectOrderException {
Rule rule = depResolver.rule;
resolveExplicitAttributes(depResolver);
@@ -231,7 +236,11 @@
}
private void resolveExplicitAttributes(final RuleResolver depResolver)
- throws InterruptedException {
+ throws InterruptedException, InconsistentAspectOrderException {
+
+ // Record error that might happen during label visitation.
+ final InconsistentAspectOrderException[] exception = new InconsistentAspectOrderException[1];
+
depResolver.attributeMap.visitLabels(
new AttributeMap.AcceptsLabelAttribute() {
@Override
@@ -242,13 +251,24 @@
|| attribute.isLateBound()) {
return;
}
- depResolver.resolveDep(new AttributeAndOwner(attribute), label);
+ try {
+ depResolver.resolveDep(new AttributeAndOwner(attribute), label);
+ } catch (InconsistentAspectOrderException e) {
+ if (exception[0] == null) {
+ exception[0] = e;
+ }
+ }
}
});
+
+ if (exception[0] != null) {
+ throw exception[0];
+ }
}
/** Resolves the dependencies for all implicit attributes in this rule. */
- private void resolveImplicitAttributes(RuleResolver depResolver) throws InterruptedException {
+ private void resolveImplicitAttributes(RuleResolver depResolver)
+ throws InterruptedException, InconsistentAspectOrderException {
// Since the attributes that come from aspects do not appear in attributeMap, we have to get
// their values from somewhere else. This incidentally means that aspects attributes are not
// configurable. It would be nice if that wasn't the case, but we'd have to revamp how
@@ -318,7 +338,8 @@
RuleResolver depResolver,
BuildConfiguration ruleConfig,
BuildConfiguration hostConfig)
- throws EvalException, InvalidConfigurationException, InterruptedException {
+ throws EvalException, InvalidConfigurationException, InconsistentAspectOrderException,
+ InterruptedException{
ConfiguredAttributeMapper attributeMap = depResolver.attributeMap;
for (AttributeAndOwner attributeAndOwner : depResolver.attributes) {
Attribute attribute = attributeAndOwner.attribute;
@@ -459,7 +480,7 @@
* @param labels the dependencies to add
*/
private void addExplicitDeps(RuleResolver depResolver, String attrName, Iterable<Label> labels)
- throws InterruptedException {
+ throws InterruptedException, InconsistentAspectOrderException {
Rule rule = depResolver.rule;
if (!rule.isAttrDefined(attrName, BuildType.LABEL_LIST)
&& !rule.isAttrDefined(attrName, BuildType.NODEP_LABEL_LIST)) {
@@ -481,7 +502,7 @@
TargetAndConfiguration node,
OrderedSetMultimap<Attribute, Label> depLabels,
NestedSetBuilder<Label> rootCauses)
- throws InterruptedException {
+ throws InterruptedException, InconsistentAspectOrderException {
Preconditions.checkArgument(node.getTarget() instanceof Rule);
Rule rule = (Rule) node.getTarget();
OrderedSetMultimap<Attribute, Dependency> outgoingEdges = OrderedSetMultimap.create();
@@ -521,11 +542,11 @@
}
- private static AspectCollection requiredAspects(
+ private AspectCollection requiredAspects(
Iterable<Aspect> aspectPath,
AttributeAndOwner attributeAndOwner,
final Target target,
- Rule originalRule) {
+ Rule originalRule) throws InconsistentAspectOrderException {
if (!(target instanceof Rule)) {
return AspectCollection.EMPTY;
}
@@ -538,17 +559,17 @@
ImmutableList.Builder<Aspect> filteredAspectPath = ImmutableList.builder();
ImmutableSet.Builder<AspectDescriptor> visibleAspects = ImmutableSet.builder();
- collectOriginatingAspects(originalRule, attributeAndOwner.attribute, (Rule) target,
+ Attribute attribute = attributeAndOwner.attribute;
+ collectOriginatingAspects(originalRule, attribute, (Rule) target,
filteredAspectPath, visibleAspects);
collectPropagatingAspects(aspectPath,
- attributeAndOwner.attribute,
+ attribute,
(Rule) target, filteredAspectPath, visibleAspects);
try {
return AspectCollection.create(filteredAspectPath.build(), visibleAspects.build());
} catch (AspectCycleOnPathException e) {
- // TODO(dslomov): propagate the error and report to user.
- throw new AssertionError(e);
+ throw new InconsistentAspectOrderException(originalRule, attribute, target, e);
}
}
@@ -603,19 +624,6 @@
}
}
- private static Iterable<Aspect> extractAspectCandidates(
- Iterable<Aspect> aspects,
- Attribute attribute, Rule originalRule) {
- ImmutableList.Builder<Aspect> aspectCandidates = ImmutableList.builder();
- aspectCandidates.addAll(attribute.getAspects(originalRule));
- for (Aspect aspect : aspects) {
- if (aspect.getDefinition().propagateAlong(attribute)) {
- aspectCandidates.add(aspect);
- }
- }
- return aspectCandidates.build();
- }
-
/**
* Pair of (attribute, owner aspect if attribute is from an aspect).
*
@@ -700,7 +708,7 @@
* apply to it.
*/
void resolveDep(AttributeAndOwner attributeAndOwner, Label depLabel)
- throws InterruptedException {
+ throws InterruptedException, InconsistentAspectOrderException {
Target toTarget = getTarget(rule, depLabel, rootCauses);
if (toTarget == null) {
return; // Skip this round: we still need to Skyframe-evaluate the dep's target.
@@ -725,7 +733,7 @@
* #resolveDep(AttributeAndOwner, Label)}.
*/
void resolveDep(AttributeAndOwner attributeAndOwner, Label depLabel, BuildConfiguration config)
- throws InterruptedException {
+ throws InterruptedException, InconsistentAspectOrderException {
Target toTarget = getTarget(rule, depLabel, rootCauses);
if (toTarget == null) {
return; // Skip this round: this is either a loading error or unevaluated Skyframe dep.
@@ -852,4 +860,27 @@
Set<Class<? extends BuildConfiguration.Fragment>> fragments,
Iterable<BuildOptions> buildOptions)
throws InvalidConfigurationException, InterruptedException;
+
+ /**
+ * Signals an inconsistency on aspect path: an aspect occurs twice on the path and
+ * the second occurrence sees a different set of aspects.
+ *
+ * {@see AspectCycleOnPathException}
+ */
+ public class InconsistentAspectOrderException extends Exception {
+ private final Location location;
+ public InconsistentAspectOrderException(Rule originalRule, Attribute attribute, Target target,
+ AspectCycleOnPathException e) {
+ super(String.format("%s (when propagating from %s to %s via attribute %s)",
+ e.getMessage(),
+ originalRule.getLabel(),
+ target.getLabel(),
+ attribute.getName()));
+ this.location = originalRule.getLocation();
+ }
+
+ public Location getLocation() {
+ return location;
+ }
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 3d5aa88..71f6912 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -21,6 +21,7 @@
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredAspectFactory;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
@@ -304,6 +305,10 @@
ConfiguredValueCreationException cause = (ConfiguredValueCreationException) e.getCause();
throw new AspectFunctionException(new AspectCreationException(
cause.getMessage(), cause.getAnalysisRootCause()));
+ } else if (e.getCause() instanceof InconsistentAspectOrderException) {
+ InconsistentAspectOrderException cause = (InconsistentAspectOrderException) e.getCause();
+ throw new AspectFunctionException(new AspectCreationException(
+ cause.getMessage()));
} else {
// Cast to InvalidConfigurationException as a consistency check. If you add any
// DependencyEvaluationException constructors, you may need to change this code, too.
@@ -519,5 +524,9 @@
public AspectFunctionException(AspectCreationException e) {
super(e, Transience.PERSISTENT);
}
+
+ public AspectFunctionException(InconsistentAspectOrderException cause) {
+ super(cause, Transience.PERSISTENT);
+ }
}
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index 673a18f..c19e3c0 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -37,6 +37,7 @@
import com.google.devtools.build.lib.analysis.ConfiguredAspect;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.Dependency;
+import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget;
import com.google.devtools.build.lib.analysis.MergedConfiguredTarget.DuplicateException;
@@ -122,6 +123,10 @@
super(cause);
}
+ public DependencyEvaluationException(InconsistentAspectOrderException cause) {
+ super(cause);
+ }
+
@Override
public synchronized Exception getCause() {
return (Exception) super.getCause();
@@ -258,6 +263,10 @@
if (e.getCause() instanceof ConfiguredValueCreationException) {
throw new ConfiguredTargetFunctionException(
(ConfiguredValueCreationException) e.getCause());
+ } else if (e.getCause() instanceof InconsistentAspectOrderException) {
+ InconsistentAspectOrderException cause = (InconsistentAspectOrderException) e.getCause();
+ throw new ConfiguredTargetFunctionException(
+ new ConfiguredValueCreationException(cause.getMessage(), target.getLabel()));
} else {
// Cast to InvalidConfigurationException as a consistency check. If you add any
// DependencyEvaluationException constructors, you may need to change this code, too.
@@ -320,6 +329,9 @@
new ConfiguredValueCreationException(e.print(), ctgValue.getLabel()));
} catch (InvalidConfigurationException e) {
throw new DependencyEvaluationException(e);
+ } catch (InconsistentAspectOrderException e) {
+ env.getListener().handle(Event.error(e.getLocation(), e.getMessage()));
+ throw new DependencyEvaluationException(e);
}
// Trim each dep's configuration so it only includes the fragments needed by its transitive
@@ -986,8 +998,13 @@
// Collect the corresponding Skyframe configured target values. Abort early if they haven't
// been computed yet.
- Collection<Dependency> configValueNames = resolver.resolveRuleLabels(
- ctgValue, configLabelMap, transitiveLoadingRootCauses);
+ Collection<Dependency> configValueNames = null;
+ try {
+ configValueNames = resolver.resolveRuleLabels(
+ ctgValue, configLabelMap, transitiveLoadingRootCauses);
+ } catch (InconsistentAspectOrderException e) {
+ throw new DependencyEvaluationException(e);
+ }
if (env.valuesMissing()) {
return null;
}
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java
index bd5eef5..7789164 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/PostConfiguredTargetFunction.java
@@ -19,6 +19,7 @@
import com.google.devtools.build.lib.actions.ActionAnalysisMetadata;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
import com.google.devtools.build.lib.analysis.Dependency;
+import com.google.devtools.build.lib.analysis.DependencyResolver.InconsistentAspectOrderException;
import com.google.devtools.build.lib.analysis.LabelAndConfiguration;
import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
@@ -111,11 +112,8 @@
deps = ConfiguredTargetFunction.getDynamicConfigurations(env, ctgValue, deps,
hostConfiguration, ruleClassProvider);
}
- } catch (EvalException e) {
- throw new PostConfiguredTargetFunctionException(e);
- } catch (ConfiguredTargetFunction.DependencyEvaluationException e) {
- throw new PostConfiguredTargetFunctionException(e);
- } catch (InvalidConfigurationException e) {
+ } catch (EvalException | ConfiguredTargetFunction.DependencyEvaluationException
+ | InvalidConfigurationException | InconsistentAspectOrderException e) {
throw new PostConfiguredTargetFunctionException(e);
}