Skip to content

Commit b42402b

Browse files
authored
Merge pull request swiftlang#40646 from slavapestov/rqm-more-validation-test-fixes
RequirementMachine: More fixes for validation tests with -requirement-machine-protocol-signatures=verify
2 parents 4eaef34 + c5df787 commit b42402b

8 files changed

+132
-45
lines changed

lib/AST/RequirementMachine/MinimalConformances.cpp

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -655,21 +655,21 @@ bool MinimalConformances::isValidConformancePath(
655655

656656
if (!foundValidConformancePath)
657657
return false;
658-
}
659-
660-
auto found = ParentPaths.find(ruleID);
661-
if (found != ParentPaths.end()) {
662-
SWIFT_DEFER {
663-
visited.erase(ruleID);
664-
};
665-
visited.insert(ruleID);
666-
667-
// If 'req' is based on some other conformance requirement
668-
// `T.[P.]A : Q', we want to make sure that we have a
669-
// non-redundant derivation for 'T : P'.
670-
if (!isValidConformancePath(visited, found->second,
671-
/*allowConcrete=*/false)) {
672-
return false;
658+
} else {
659+
auto found = ParentPaths.find(ruleID);
660+
if (found != ParentPaths.end()) {
661+
SWIFT_DEFER {
662+
visited.erase(ruleID);
663+
};
664+
visited.insert(ruleID);
665+
666+
// If 'req' is based on some other conformance requirement
667+
// `T.[P.]A : Q', we want to make sure that we have a
668+
// non-redundant derivation for 'T : P'.
669+
if (!isValidConformancePath(visited, found->second,
670+
/*allowConcrete=*/false)) {
671+
return false;
672+
}
673673
}
674674
}
675675
}
@@ -868,6 +868,9 @@ void MinimalConformances::computeMinimalConformances(bool firstPass) {
868868
llvm::dbgs() << " pass: ";
869869
llvm::dbgs() << System.getRule(ruleID).getLHS();
870870
llvm::dbgs() << "\n";
871+
llvm::dbgs() << "-- via valid path: ";
872+
dumpConformancePath(llvm::errs(), path);
873+
llvm::dbgs() << "\n";
871874
}
872875

873876
RedundantConformances.insert(ruleID);
@@ -897,6 +900,7 @@ void MinimalConformances::verifyMinimalConformances() const {
897900
llvm::errs() << "Redundant conformance is not recoverable:\n";
898901
llvm::errs() << rule << "\n\n";
899902
dumpMinimalConformanceEquations(llvm::errs());
903+
dumpMinimalConformances(llvm::errs());
900904
abort();
901905
}
902906

@@ -907,6 +911,7 @@ void MinimalConformances::verifyMinimalConformances() const {
907911
llvm::errs() << "Minimal conformance contains unresolved symbols: ";
908912
llvm::errs() << rule << "\n\n";
909913
dumpMinimalConformanceEquations(llvm::errs());
914+
dumpMinimalConformances(llvm::errs());
910915
abort();
911916
}
912917
}

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,10 @@ 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-
bool PropertyMap::addProperty(
312+
///
313+
/// If there was a conflict, returns the conflicting rule ID; otherwise
314+
/// returns None.
315+
Optional<unsigned> PropertyMap::addProperty(
313316
Term key, Symbol property, unsigned ruleID,
314317
SmallVectorImpl<InducedRule> &inducedRules) {
315318
assert(property.isProperty());
@@ -376,10 +379,22 @@ PropertyMap::buildPropertyMap(unsigned maxIterations,
376379

377380
for (const auto &bucket : properties) {
378381
for (auto property : bucket) {
379-
bool conflict = addProperty(property.key, property.symbol,
380-
property.ruleID, inducedRules);
381-
if (conflict)
382-
System.getRule(property.ruleID).markConflicting();
382+
auto existingRuleID = addProperty(property.key, property.symbol,
383+
property.ruleID, inducedRules);
384+
if (existingRuleID) {
385+
// The GSB only dropped the new rule in the case of a conflicting
386+
// superclass requirement, so maintain that behavior here.
387+
auto &existingRule = System.getRule(*existingRuleID);
388+
if (existingRule.isPropertyRule()->getKind() !=
389+
Symbol::Kind::Superclass) {
390+
if (existingRule.getRHS().size() == property.key.size())
391+
existingRule.markConflicting();
392+
}
393+
394+
auto &newRule = System.getRule(property.ruleID);
395+
assert(newRule.getRHS().size() == property.key.size());
396+
newRule.markConflicting();
397+
}
383398
}
384399
}
385400

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ class PropertyBag {
101101

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

104-
bool addProperty(Symbol property,
105-
unsigned ruleID,
106-
RewriteContext &ctx,
107-
SmallVectorImpl<InducedRule> &inducedRules,
108-
bool debug);
104+
Optional<unsigned> addProperty(Symbol property,
105+
unsigned ruleID,
106+
RewriteContext &ctx,
107+
SmallVectorImpl<InducedRule> &inducedRules,
108+
bool debug);
109109
void copyPropertiesFrom(const PropertyBag *next,
110110
RewriteContext &ctx);
111111

@@ -204,8 +204,9 @@ class PropertyMap {
204204

205205
private:
206206
void clear();
207-
bool addProperty(Term key, Symbol property, unsigned ruleID,
208-
SmallVectorImpl<InducedRule> &inducedRules);
207+
Optional<unsigned>
208+
addProperty(Term key, Symbol property, unsigned ruleID,
209+
SmallVectorImpl<InducedRule> &inducedRules);
209210

210211
void computeConcreteTypeInDomainMap();
211212
void concretizeNestedTypesFromConcreteParents(

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -307,8 +307,9 @@ static std::pair<Symbol, bool> unifySuperclasses(
307307
return std::make_pair(rhs, false);
308308
}
309309

310-
/// Returns true if there was a conflict.
311-
bool PropertyBag::addProperty(
310+
/// Returns the old conflicting rule ID if there was a conflict,
311+
/// otherwise returns None.
312+
Optional<unsigned> PropertyBag::addProperty(
312313
Symbol property, unsigned ruleID, RewriteContext &ctx,
313314
SmallVectorImpl<InducedRule> &inducedRules,
314315
bool debug) {
@@ -317,19 +318,20 @@ bool PropertyBag::addProperty(
317318
case Symbol::Kind::Protocol:
318319
ConformsTo.push_back(property.getProtocol());
319320
ConformsToRules.push_back(ruleID);
320-
return false;
321+
return None;
321322

322323
case Symbol::Kind::Layout:
323324
if (!Layout) {
324325
Layout = property.getLayoutConstraint();
325326
LayoutRule = ruleID;
326327
} else {
328+
assert(LayoutRule.hasValue());
327329
Layout = Layout.merge(property.getLayoutConstraint());
328330
if (!Layout->isKnownLayout())
329-
return true;
331+
return LayoutRule;
330332
}
331333

332-
return false;
334+
return None;
333335

334336
case Symbol::Kind::Superclass: {
335337
// FIXME: Also handle superclass vs concrete
@@ -338,34 +340,36 @@ bool PropertyBag::addProperty(
338340
Superclass = property;
339341
SuperclassRule = ruleID;
340342
} else {
343+
assert(SuperclassRule.hasValue());
341344
auto pair = unifySuperclasses(*Superclass, property,
342345
ctx, inducedRules, debug);
343346
Superclass = pair.first;
344347
bool conflict = pair.second;
345348
if (conflict)
346-
return true;
349+
return SuperclassRule;
347350
}
348351

349-
return false;
352+
return None;
350353
}
351354

352355
case Symbol::Kind::ConcreteType: {
353356
if (!ConcreteType) {
354357
ConcreteType = property;
355358
ConcreteTypeRule = ruleID;
356359
} else {
360+
assert(ConcreteTypeRule.hasValue());
357361
bool conflict = unifyConcreteTypes(*ConcreteType, property,
358362
ctx, inducedRules, debug);
359363
if (conflict)
360-
return true;
364+
return ConcreteTypeRule;
361365
}
362366

363-
return false;
367+
return None;
364368
}
365369

366370
case Symbol::Kind::ConcreteConformance:
367371
// FIXME
368-
return false;
372+
return None;
369373

370374
case Symbol::Kind::Name:
371375
case Symbol::Kind::GenericParam:
@@ -533,10 +537,13 @@ void PropertyMap::concretizeNestedTypesFromConcreteParent(
533537
// With concrete types, a missing conformance is a conflict.
534538
if (requirementKind == RequirementKind::SameType) {
535539
// FIXME: Diagnose conflict
536-
//
537-
// FIXME: We should mark the more specific rule of the two
538-
// as conflicting.
539-
System.getRule(conformanceRuleID).markConflicting();
540+
auto &concreteRule = System.getRule(concreteRuleID);
541+
if (concreteRule.getRHS().size() == key.size())
542+
concreteRule.markConflicting();
543+
544+
auto &conformanceRule = System.getRule(conformanceRuleID);
545+
if (conformanceRule.getRHS().size() == key.size())
546+
conformanceRule.markConflicting();
540547
}
541548

542549
if (Debug.contains(DebugFlags::ConcretizeNestedTypes)) {

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -505,9 +505,9 @@ TypeAliasRequirementsRequest::evaluate(Evaluator &evaluator,
505505
for (auto *inheritedProto : ctx.getRewriteContext().getInheritedProtocols(proto)) {
506506
for (auto req : inheritedProto->getMembers()) {
507507
if (auto *typeReq = dyn_cast<TypeDecl>(req)) {
508-
// Ignore generic typealiases.
509-
if (auto typeAliasReq = dyn_cast<TypeAliasDecl>(typeReq))
510-
if (typeAliasReq->isGeneric())
508+
// Ignore generic types.
509+
if (auto genReq = dyn_cast<GenericTypeDecl>(req))
510+
if (genReq->getGenericParams())
511511
continue;
512512

513513
inheritedTypeDecls[typeReq->getName()].push_back(typeReq);

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ bool Rule::isProtocolRefinementRule() const {
9898
RHS.size() == 1 &&
9999
LHS[0] == RHS[0] &&
100100
LHS[0].getKind() == Symbol::Kind::Protocol &&
101-
LHS[1].getKind() == Symbol::Kind::Protocol &&
101+
(LHS[1].getKind() == Symbol::Kind::Protocol ||
102+
LHS[1].getKind() == Symbol::Kind::ConcreteConformance) &&
102103
LHS[0] != LHS[1]) {
103104

104105
// A protocol refinement rule must be from a directly-stated
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
2+
3+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P1@
4+
// CHECK-NEXT: Requirement signature: <Self>
5+
6+
protocol P1 {}
7+
8+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P2@
9+
// CHECK-NEXT: Requirement signature: <Self where Self.A : P1, Self.B : P2>
10+
11+
protocol P2 {
12+
associatedtype A: P1
13+
associatedtype B: P2
14+
}
15+
16+
struct Concrete: P1, P2 {
17+
typealias A = Concrete
18+
typealias B = Concrete
19+
}
20+
21+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P3a@
22+
// CHECK-NEXT: Requirement signature: <Self where Self.T : P2>
23+
24+
protocol P3a {
25+
associatedtype T : P2
26+
}
27+
28+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P3b@
29+
// CHECK-NEXT: Requirement signature: <Self where Self.T : P2, Self.T.A == Self.T.B>
30+
31+
protocol P3b {
32+
associatedtype T : P2 where T.A == T.B
33+
}
34+
35+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P4a@
36+
// CHECK-NEXT: Requirement signature: <Self where Self : P3a, Self.T == Concrete>
37+
38+
protocol P4a : P3a where T.A == T.B, T == Concrete {}
39+
40+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P4b@
41+
// CHECK-NEXT: Requirement signature: <Self where Self : P3b, Self.T == Concrete>
42+
43+
protocol P4b : P3b where T == Concrete {}
44+
45+
// CHECK-LABEL: redundant_parent_path_in_protocol.(file).P5@
46+
// CHECK-NEXT: Requirement signature: <Self where Self.T == Concrete>
47+
48+
protocol P5 {
49+
associatedtype T : P2 where T.A == T.B, T == Concrete
50+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
2+
3+
protocol P {}
4+
class C : P {}
5+
6+
// CHECK-LABEL: redundant_protocol_inheritance_via_concrete.(file).Q@
7+
// CHECK-NEXT: Requirement signature: <Self where Self : C>
8+
protocol Q : P, C {}

0 commit comments

Comments
 (0)