Skip to content

Commit 7a56ab8

Browse files
committed
RequirementMachine: Mark conflicting rules
This isn't quite right, because we really want the longer (more specific) of the two rules to be conflicting, not the most-recently added rule.
1 parent 5ac43b1 commit 7a56ab8

File tree

7 files changed

+76
-32
lines changed

7 files changed

+76
-32
lines changed

lib/AST/RequirementMachine/HomotopyReduction.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -523,16 +523,19 @@ void RewriteSystem::minimizeRewriteSystem() {
523523

524524
/// In a conformance-valid rewrite system, any rule with unresolved symbols on
525525
/// the left or right hand side should have been simplified by another rule.
526-
bool RewriteSystem::hasNonRedundantUnresolvedRules() const {
526+
bool RewriteSystem::hadError() const {
527527
assert(Complete);
528528
assert(Minimized);
529529

530530
for (const auto &rule : Rules) {
531-
if (!rule.isRedundant() &&
532-
!rule.isPermanent() &&
533-
rule.containsUnresolvedSymbols()) {
531+
if (rule.isPermanent())
532+
continue;
533+
534+
if (rule.isConflicting())
535+
return true;
536+
537+
if (!rule.isRedundant() && rule.containsUnresolvedSymbols())
534538
return true;
535-
}
536539
}
537540

538541
return false;
@@ -555,6 +558,7 @@ RewriteSystem::getMinimizedProtocolRules(
555558

556559
if (rule.isPermanent() ||
557560
rule.isRedundant() ||
561+
rule.isConflicting() ||
558562
rule.containsUnresolvedSymbols()) {
559563
continue;
560564
}
@@ -584,6 +588,7 @@ RewriteSystem::getMinimizedGenericSignatureRules() const {
584588

585589
if (rule.isPermanent() ||
586590
rule.isRedundant() ||
591+
rule.isConflicting() ||
587592
rule.containsUnresolvedSymbols()) {
588593
continue;
589594
}

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,15 @@ void PropertyMap::clear() {
309309

310310
/// Record a protocol conformance, layout or superclass constraint on the given
311311
/// key. Must be called in monotonically non-decreasing key order.
312-
void PropertyMap::addProperty(
312+
bool PropertyMap::addProperty(
313313
Term key, Symbol property, unsigned ruleID,
314314
SmallVectorImpl<InducedRule> &inducedRules) {
315315
assert(property.isProperty());
316316
assert(*System.getRule(ruleID).isPropertyRule() == property);
317317
auto *props = getOrCreateProperties(key);
318-
props->addProperty(property, ruleID, Context,
319-
inducedRules, Debug.contains(DebugFlags::ConcreteUnification));
318+
bool debug = Debug.contains(DebugFlags::ConcreteUnification);
319+
return props->addProperty(property, ruleID, Context,
320+
inducedRules, debug);
320321
}
321322

322323
/// Build the property map from all rules of the form T.[p] => T, where
@@ -375,7 +376,10 @@ PropertyMap::buildPropertyMap(unsigned maxIterations,
375376

376377
for (const auto &bucket : properties) {
377378
for (auto property : bucket) {
378-
addProperty(property.key, property.symbol, property.ruleID, inducedRules);
379+
bool conflict = addProperty(property.key, property.symbol,
380+
property.ruleID, inducedRules);
381+
if (conflict)
382+
System.getRule(property.ruleID).markConflicting();
379383
}
380384
}
381385

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ class PropertyBag {
100100

101101
explicit PropertyBag(Term key) : Key(key) {}
102102

103-
void addProperty(Symbol property,
103+
bool addProperty(Symbol property,
104104
unsigned ruleID,
105105
RewriteContext &ctx,
106106
SmallVectorImpl<InducedRule> &inducedRules,
@@ -202,7 +202,7 @@ class PropertyMap {
202202

203203
private:
204204
void clear();
205-
void addProperty(Term key, Symbol property, unsigned ruleID,
205+
bool addProperty(Term key, Symbol property, unsigned ruleID,
206206
SmallVectorImpl<InducedRule> &inducedRules);
207207

208208
void computeConcreteTypeInDomainMap();

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ static bool unifyConcreteTypes(
250250
///
251251
/// Returns the most derived superclass, which becomes the new superclass
252252
/// that gets recorded in the property map.
253-
static Symbol unifySuperclasses(
253+
static std::pair<Symbol, bool> unifySuperclasses(
254254
Symbol lhs, Symbol rhs, RewriteContext &ctx,
255255
SmallVectorImpl<InducedRule> &inducedRules,
256256
bool debug) {
@@ -282,7 +282,7 @@ static Symbol unifySuperclasses(
282282
llvm::dbgs() << "%% Unrelated superclass types\n";
283283
}
284284

285-
return lhs;
285+
return std::make_pair(lhs, true);
286286
}
287287

288288
if (lhsClass != rhsClass) {
@@ -300,14 +300,15 @@ static Symbol unifySuperclasses(
300300
if (debug) {
301301
llvm::dbgs() << "%% Superclass conflict\n";
302302
}
303-
return rhs;
303+
return std::make_pair(rhs, true);
304304
}
305305

306306
// Record the more specific class.
307-
return rhs;
307+
return std::make_pair(rhs, false);
308308
}
309309

310-
void PropertyBag::addProperty(
310+
/// Returns true if there was a conflict.
311+
bool PropertyBag::addProperty(
311312
Symbol property, unsigned ruleID, RewriteContext &ctx,
312313
SmallVectorImpl<InducedRule> &inducedRules,
313314
bool debug) {
@@ -316,46 +317,55 @@ void PropertyBag::addProperty(
316317
case Symbol::Kind::Protocol:
317318
ConformsTo.push_back(property.getProtocol());
318319
ConformsToRules.push_back(ruleID);
319-
return;
320+
return false;
320321

321322
case Symbol::Kind::Layout:
322323
if (!Layout) {
323324
Layout = property.getLayoutConstraint();
324325
LayoutRule = ruleID;
325-
} else
326+
} else {
326327
Layout = Layout.merge(property.getLayoutConstraint());
328+
if (!Layout->isKnownLayout())
329+
return true;
330+
}
327331

328-
return;
332+
return false;
329333

330334
case Symbol::Kind::Superclass: {
331335
// FIXME: Also handle superclass vs concrete
332336

333-
if (Superclass) {
334-
Superclass = unifySuperclasses(*Superclass, property,
335-
ctx, inducedRules, debug);
336-
} else {
337+
if (!Superclass) {
337338
Superclass = property;
338339
SuperclassRule = ruleID;
340+
} else {
341+
auto pair = unifySuperclasses(*Superclass, property,
342+
ctx, inducedRules, debug);
343+
Superclass = pair.first;
344+
bool conflict = pair.second;
345+
if (conflict)
346+
return true;
339347
}
340348

341-
return;
349+
return false;
342350
}
343351

344352
case Symbol::Kind::ConcreteType: {
345-
if (ConcreteType) {
346-
(void) unifyConcreteTypes(*ConcreteType, property,
347-
ctx, inducedRules, debug);
348-
} else {
353+
if (!ConcreteType) {
349354
ConcreteType = property;
350355
ConcreteTypeRule = ruleID;
356+
} else {
357+
bool conflict = unifyConcreteTypes(*ConcreteType, property,
358+
ctx, inducedRules, debug);
359+
if (conflict)
360+
return true;
351361
}
352362

353-
return;
363+
return false;
354364
}
355365

356366
case Symbol::Kind::ConcreteConformance:
357367
// FIXME
358-
return;
368+
return false;
359369

360370
case Symbol::Kind::Name:
361371
case Symbol::Kind::GenericParam:

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ bool RequirementMachine::isComplete() const {
279279
bool RequirementMachine::hadError() const {
280280
// FIXME: Implement other checks here
281281
// FIXME: Assert if hadError() is true but we didn't emit any diagnostics?
282-
return System.hasNonRedundantUnresolvedRules();
282+
return System.hadError();
283283
}
284284

285285
void RequirementMachine::dump(llvm::raw_ostream &out) const {

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,8 @@ void Rule::dump(llvm::raw_ostream &out) const {
150150
out << " [simplified]";
151151
if (Redundant)
152152
out << " [redundant]";
153+
if (Conflicting)
154+
out << "[conflicting]";
153155
}
154156

155157
RewriteSystem::RewriteSystem(RewriteContext &ctx)

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,25 @@ class Rule final {
6666
/// set of requirements in a generic signature.
6767
unsigned Redundant : 1;
6868

69+
/// A 'conflicting' rule is a property rule which cannot be satisfied by any
70+
/// concrete type because it is mutually exclusive with some other rule.
71+
/// An example would be a pair of concrete type rules:
72+
///
73+
/// T.[concrete: Int] => T
74+
/// T.[concrete: String] => T
75+
///
76+
/// Conflicting rules are detected in property map construction, and are
77+
/// dropped from the minimal set of requirements.
78+
unsigned Conflicting : 1;
79+
6980
public:
7081
Rule(Term lhs, Term rhs)
7182
: LHS(lhs), RHS(rhs) {
7283
Permanent = false;
7384
Explicit = false;
7485
Simplified = false;
7586
Redundant = false;
87+
Conflicting = false;
7688
}
7789

7890
const Term &getLHS() const { return LHS; }
@@ -105,6 +117,10 @@ class Rule final {
105117
return Redundant;
106118
}
107119

120+
bool isConflicting() const {
121+
return Conflicting;
122+
}
123+
108124
bool containsUnresolvedSymbols() const {
109125
return (LHS.containsUnresolvedSymbols() ||
110126
RHS.containsUnresolvedSymbols());
@@ -132,6 +148,13 @@ class Rule final {
132148
Redundant = true;
133149
}
134150

151+
void markConflicting() {
152+
// It's okay to mark a rule as conflicting multiple times, but it must not
153+
// be a permanent rule.
154+
assert(!Permanent && "Permanent rule should not conflict with anything");
155+
Conflicting = true;
156+
}
157+
135158
unsigned getDepth() const;
136159

137160
int compare(const Rule &other, RewriteContext &ctx) const;
@@ -356,7 +379,7 @@ class RewriteSystem final {
356379
public:
357380
void minimizeRewriteSystem();
358381

359-
bool hasNonRedundantUnresolvedRules() const;
382+
bool hadError() const;
360383

361384
llvm::DenseMap<const ProtocolDecl *, std::vector<unsigned>>
362385
getMinimizedProtocolRules(ArrayRef<const ProtocolDecl *> protos) const;

0 commit comments

Comments
 (0)