Change allowedRuleClasses/mandatoryProviders semantics to "either-or" instead of "and".
Also allow native rules to require declared providers on their
dependencies.
--
MOS_MIGRATED_REVID=135454750
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 49f1c92..5e6d506 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
@@ -70,6 +70,7 @@
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.packages.RuleErrorConsumer;
+import com.google.devtools.build.lib.packages.SkylarkProviderIdentifier;
import com.google.devtools.build.lib.packages.Target;
import com.google.devtools.build.lib.packages.TargetUtils;
import com.google.devtools.build.lib.rules.AliasProvider;
@@ -88,6 +89,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -1788,16 +1790,17 @@
}
private String getMissingMandatoryProviders(ConfiguredTarget prerequisite, Attribute attribute){
- List<ImmutableSet<String>> mandatoryProvidersList = attribute.getMandatoryProvidersList();
+ ImmutableList<ImmutableSet<SkylarkProviderIdentifier>> mandatoryProvidersList
+ = attribute.getMandatoryProvidersList();
if (mandatoryProvidersList.isEmpty()) {
return null;
}
List<List<String>> missingProvidersList = new ArrayList<>();
- for (ImmutableSet<String> providers : mandatoryProvidersList) {
+ for (ImmutableSet<SkylarkProviderIdentifier> providers : mandatoryProvidersList) {
List<String> missing = new ArrayList<>();
- for (String provider : providers) {
+ for (SkylarkProviderIdentifier provider : providers) {
if (prerequisite.get(provider) == null) {
- missing.add(provider);
+ missing.add(provider.toString());
}
}
if (missing.isEmpty()) {
@@ -1864,30 +1867,36 @@
private void validateRuleDependency(ConfiguredTarget prerequisite, Attribute attribute) {
Target prerequisiteTarget = prerequisite.getTarget();
RuleClass ruleClass = ((Rule) prerequisiteTarget).getRuleClassObject();
- HashSet<String> unfulfilledRequirements = new HashSet<>();
+ String notAllowedRuleClassesMessage = null;
if (attribute.getAllowedRuleClassesPredicate() != Predicates.<RuleClass>alwaysTrue()) {
if (attribute.getAllowedRuleClassesPredicate().apply(ruleClass)) {
+ // prerequisite has an allowed rule class => accept.
return;
}
- unfulfilledRequirements.add(badPrerequisiteMessage(prerequisiteTarget.getTargetKind(),
- prerequisite, "expected " + attribute.getAllowedRuleClassesPredicate(), false));
+ // remember that the rule class that was not allowed;
+ // but maybe prerequisite provides required providers? do not reject yet.
+ notAllowedRuleClassesMessage =
+ badPrerequisiteMessage(
+ prerequisiteTarget.getTargetKind(),
+ prerequisite,
+ "expected " + attribute.getAllowedRuleClassesPredicate(),
+ false);
}
- if (attribute.getAllowedRuleClassesWarningPredicate()
- != Predicates.<RuleClass>alwaysTrue()) {
+ if (attribute.getAllowedRuleClassesWarningPredicate() != Predicates.<RuleClass>alwaysTrue()) {
Predicate<RuleClass> warningPredicate = attribute.getAllowedRuleClassesWarningPredicate();
if (warningPredicate.apply(ruleClass)) {
reportBadPrerequisite(attribute, prerequisiteTarget.getTargetKind(), prerequisite,
"expected " + attribute.getAllowedRuleClassesPredicate(), true);
+ // prerequisite has a rule class allowed with a warning => accept, emitting a warning.
return;
}
}
- // This condition is required; getMissingMandatory[Native]Providers() would be vacuously true
- // if no providers were mandatory (thus, none are missing), which would cause an early return
- // below without emitting the error message about the not-allowed rule class if that
- // requirement was unfulfilled.
+ // If we got there, we have no allowed rule class.
+ // If mandatory providers are specified, try them.
+ Set<String> unfulfilledRequirements = new LinkedHashSet<>();
if (!attribute.getMandatoryNativeProvidersList().isEmpty()
|| !attribute.getMandatoryProvidersList().isEmpty()) {
boolean hadAllMandatoryProviders = true;
@@ -1909,10 +1918,16 @@
}
if (hadAllMandatoryProviders) {
+ // all mandatory providers are present => accept.
return;
}
}
+ // not allowed rule class and some mandatory providers missing => reject.
+ if (notAllowedRuleClassesMessage != null) {
+ unfulfilledRequirements.add(notAllowedRuleClassesMessage);
+ }
+
if (!unfulfilledRequirements.isEmpty()) {
attributeError(
attribute.getName(), StringUtil.joinEnglishList(unfulfilledRequirements, "and"));