Simplify split transition semantics: noops now return the input build options.
This results in less special logic in the implementation and a simpler API.
PiperOrigin-RevId: 197772283
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 dd34f19..a72b346 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
@@ -403,8 +403,15 @@
LateBoundDefault<?, ?> lateBoundDefault = attribute.getLateBoundDefault();
- Collection<BuildOptions> splitOptions = getSplitOptions(attributeMap, attribute, ruleConfig);
- if (!splitOptions.isEmpty() && !ruleConfig.isHostConfiguration()) {
+ boolean hasSplitTransition = false;
+ List<BuildOptions> splitOptions = null;
+ if (attribute.hasSplitConfigurationTransition()) {
+ splitOptions =
+ attribute.getSplitTransition(attributeMap).checkedSplit(ruleConfig.getOptions());
+ hasSplitTransition = !SplitTransition.equals(ruleConfig.getOptions(), splitOptions);
+ }
+
+ if (hasSplitTransition && !ruleConfig.isHostConfiguration()) {
// Late-bound attribute with a split transition:
// Since we want to get the same results as TransitionResolver.evaluateTransition (but
// skip it since we've already applied the split), we want to make sure this logic
@@ -449,24 +456,6 @@
}
/**
- * Returns the BuildOptions if the rule's attribute triggers a split in this configuration, or
- * the empty collection if the attribute does not trigger a split transition or if the split
- * transition does not apply.
- *
- * <p>Even though the attribute may have a split, splits don't have to apply in every
- * configuration (see {@link SplitTransition#split}).
- */
- private static Collection<BuildOptions> getSplitOptions(ConfiguredAttributeMapper attributeMap,
- Attribute attribute,
- BuildConfiguration ruleConfig) {
- if (!attribute.hasSplitConfigurationTransition()) {
- return ImmutableList.<BuildOptions>of();
- }
- SplitTransition transition = attribute.getSplitTransition(attributeMap);
- return transition.split(ruleConfig.getOptions());
- }
-
- /**
* Returns the label dependencies for the given late-bound attribute in this rule.
*
* @param rule the rule being evaluated
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
index adfeb58..fb17814 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java
@@ -790,10 +790,11 @@
SplitTransition transition =
attributeDefinition.getSplitTransition(
ConfiguredAttributeMapper.of(rule, configConditions));
- List<BuildOptions> splitOptions = transition.split(getConfiguration().getOptions());
+ BuildOptions fromOptions = getConfiguration().getOptions();
+ List<BuildOptions> splitOptions = transition.checkedSplit(fromOptions);
List<ConfiguredTargetAndData> deps = getConfiguredTargetAndTargetDeps(attributeName);
- if (splitOptions.isEmpty()) {
+ if (SplitTransition.equals(fromOptions, splitOptions)) {
// The split transition is not active. Defer the decision on which CPU to use.
return ImmutableMap.of(Optional.<String>absent(), deps);
}
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
index 677c028..531c6f1 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigurationResolver.java
@@ -261,7 +261,7 @@
// resolveAspectDependencies don't get a chance to make their own Skyframe requests before
// bailing out of this ConfiguredTargetFunction call. Ideally we could batch all requests
// from all methods into a single Skyframe call, but there are enough subtle data flow
- // dependencies in ConfiguredTargetFucntion to make that impractical.
+ // dependencies in ConfiguredTargetFunction to make that impractical.
Map<SkyKey, ValueOrException<InvalidConfigurationException>> depConfigValues =
env.getValuesOrThrow(keysToEntries.keySet(), InvalidConfigurationException.class);
@@ -429,14 +429,7 @@
// TODO(bazel-team): safety-check that this never mutates fromOptions.
result = ImmutableList.of(((PatchTransition) transition).patch(fromOptions));
} else if (transition instanceof SplitTransition) {
- List<BuildOptions> toOptions = ((SplitTransition) transition).split(fromOptions);
- if (toOptions.isEmpty()) {
- // When the split returns an empty list, it's signaling it doesn't apply to this instance.
- // So return the original options.
- result = ImmutableList.<BuildOptions>of(fromOptions);
- } else {
- result = toOptions;
- }
+ return ((SplitTransition) transition).checkedSplit(fromOptions);
} else {
throw new IllegalStateException(String.format(
"unsupported config transition type: %s", transition.getClass().getName()));
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingSplitTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingSplitTransition.java
index 69970c2..71e3770 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingSplitTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/ComposingSplitTransition.java
@@ -120,13 +120,7 @@
if (transition instanceof PatchTransition) {
return ImmutableList.<BuildOptions>of(((PatchTransition) transition).patch(fromOptions));
} else if (transition instanceof SplitTransition) {
- SplitTransition split = (SplitTransition) transition;
- List<BuildOptions> splitOptions = split.split(fromOptions);
- if (splitOptions.isEmpty()) {
- return ImmutableList.<BuildOptions>of(fromOptions);
- } else {
- return splitOptions;
- }
+ return ((SplitTransition) transition).checkedSplit(fromOptions);
} else {
throw new IllegalStateException(
String.format("Unsupported composite transition type: %s",
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/SplitTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/SplitTransition.java
index 05ecfaa..eb71869 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/SplitTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/transitions/SplitTransition.java
@@ -14,6 +14,8 @@
package com.google.devtools.build.lib.analysis.config.transitions;
+import com.google.common.base.Verify;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.concurrent.ThreadSafety;
import java.util.List;
@@ -27,7 +29,29 @@
@FunctionalInterface
public interface SplitTransition extends ConfigurationTransition {
/**
- * Return the list of {@code BuildOptions} after splitting; empty if not applicable.
+ * Returns the list of {@code BuildOptions} after splitting, or the original options if this
+ * split is a noop.
+ *
+ * <p>Returning an empty or null list triggers a {@link RuntimeException}.
*/
List<BuildOptions> split(BuildOptions buildOptions);
+
+ /**
+ * Calls {@link #split} and throws a {@link RuntimeException} if the split output is empty.
+ */
+ default List<BuildOptions> checkedSplit(BuildOptions buildOptions) {
+ List<BuildOptions> splitOptions = split(buildOptions);
+ Verify.verifyNotNull(splitOptions, "Split transition output may not be null");
+ Verify.verify(!splitOptions.isEmpty(), "Split transition output may not be empty");
+ return splitOptions;
+ }
+
+ /**
+ * Returns true iff {@code option} and {@splitOptions} are equal.
+ *
+ * <p>This can be used to determine if a split is a noop.
+ */
+ static boolean equals(BuildOptions options, List<BuildOptions> splitOptions) {
+ return splitOptions.size() == 1 && Iterables.getOnlyElement(splitOptions).equals(options);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 2035a79..815616d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -238,7 +238,7 @@
if (androidOptions.cpu.isEmpty()
|| androidCrosstoolTop == null
|| androidCrosstoolTop.equals(cppOptions.crosstoolTop)) {
- return ImmutableList.of();
+ return ImmutableList.of(buildOptions);
} else {