Implement proper error handling for interleaved loading and analysis.
Add test coverage by re-running BuildViewTest with the new Skyframe loading
phase runner.
--
MOS_MIGRATED_REVID=113517509
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 dba5155..1224c3e 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
@@ -73,6 +73,7 @@
import com.google.devtools.build.skyframe.ValueOrException2;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -85,6 +86,10 @@
* SkyFunction for {@link ConfiguredTargetValue}s.
*/
final class ConfiguredTargetFunction implements SkyFunction {
+ // This construction is a bit funky, but guarantees that the Object reference here is globally
+ // unique.
+ static final Set<ConfigMatchingProvider> NO_CONFIG_CONDITIONS =
+ Collections.unmodifiableSet(ImmutableSet.<ConfigMatchingProvider>of());
/**
* Exception class that signals an error during the evaluation of a dependency.
@@ -138,19 +143,27 @@
if (packageValue == null) {
return null;
}
+
+ // TODO(ulfjack): This tries to match the logic in TransitiveTargetFunction /
+ // TargetMarkerFunction. Maybe we can merge the two?
Package pkg = packageValue.getPackage();
- if (pkg.containsErrors()) {
- throw new ConfiguredTargetFunctionException(
- new BuildFileContainsErrorsException(lc.getLabel().getPackageIdentifier()));
- }
Target target;
try {
- target = packageValue.getPackage().getTarget(lc.getLabel().getName());
+ target = pkg.getTarget(lc.getLabel().getName());
} catch (NoSuchTargetException e) {
- throw new ConfiguredTargetFunctionException(e);
+ throw new ConfiguredTargetFunctionException(
+ new ConfiguredValueCreationException(e.getMessage()));
}
-
- transitivePackages.add(packageValue.getPackage());
+ if (pkg.containsErrors()) {
+ if (target == null) {
+ throw new ConfiguredTargetFunctionException(new ConfiguredValueCreationException(
+ new BuildFileContainsErrorsException(
+ lc.getLabel().getPackageIdentifier()).getMessage()));
+ } else {
+ transitiveLoadingRootCauses.add(lc.getLabel());
+ }
+ }
+ transitivePackages.add(pkg);
// TODO(bazel-team): This is problematic - we create the right key, but then end up with a value
// that doesn't match; we can even have the same value multiple times. However, I think it's
// only triggered in tests (i.e., in normal operation, the configuration passed in is already
@@ -158,11 +171,9 @@
if (!target.isConfigurable()) {
configuration = null;
}
+ TargetAndConfiguration ctgValue = new TargetAndConfiguration(target, configuration);
SkyframeDependencyResolver resolver = view.createDependencyResolver(env);
-
- TargetAndConfiguration ctgValue =
- new TargetAndConfiguration(target, configuration);
try {
// Get the configuration targets that trigger this rule's configurable attributes.
Set<ConfigMatchingProvider> configConditions = getConfigConditions(
@@ -171,6 +182,17 @@
if (env.valuesMissing()) {
return null;
}
+ // TODO(ulfjack): ConfiguredAttributeMapper (indirectly used from computeDependencies) isn't
+ // safe to use if there are missing config conditions, so we stop here, but only if there are
+ // config conditions - though note that we can't check if configConditions is non-empty - it
+ // may be empty for other reasons. It would be better to continue here so that we can collect
+ // more root causes during computeDependencies.
+ // Note that this doesn't apply to AspectFunction, because aspects can't have configurable
+ // attributes.
+ if (!transitiveLoadingRootCauses.isEmpty() && configConditions != NO_CONFIG_CONDITIONS) {
+ throw new ConfiguredTargetFunctionException(
+ new ConfiguredValueCreationException(transitiveLoadingRootCauses.build()));
+ }
ListMultimap<Attribute, ConfiguredTarget> depValueMap =
computeDependencies(
@@ -654,7 +676,7 @@
NestedSetBuilder<Label> transitiveLoadingRootCauses)
throws DependencyEvaluationException {
if (!(target instanceof Rule)) {
- return ImmutableSet.of();
+ return NO_CONFIG_CONDITIONS;
}
ImmutableSet.Builder<ConfigMatchingProvider> configConditions = ImmutableSet.builder();
@@ -672,7 +694,7 @@
}
}
if (configLabelMap.isEmpty()) {
- return ImmutableSet.of();
+ return NO_CONFIG_CONDITIONS;
}
// Collect the corresponding Skyframe configured target values. Abort early if they haven't