Skip to content

Commit 9bb497c

Browse files
committed
RequirementMachine: Concrete class requirements imply superclass requirements
1 parent be772cc commit 9bb497c

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

lib/AST/RequirementMachine/PropertyMap.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ PropertyMap::buildPropertyMap(unsigned maxIterations,
368368
}
369369
}
370370

371+
// Now, check for conflicts between superclass and concrete type rules.
372+
checkConcreteTypeRequirements(inducedRules);
373+
371374
// We collect terms with fully concrete types so that we can re-use them
372375
// to tie off recursion in the next step.
373376
computeConcreteTypeInDomainMap();

lib/AST/RequirementMachine/PropertyMap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ class PropertyMap {
232232
void addProperty(Term key, Symbol property, unsigned ruleID,
233233
SmallVectorImpl<InducedRule> &inducedRules);
234234

235+
void checkConcreteTypeRequirements(
236+
SmallVectorImpl<InducedRule> &inducedRules);
237+
235238
void computeConcreteTypeInDomainMap();
236239
void concretizeNestedTypesFromConcreteParents(
237240
SmallVectorImpl<InducedRule> &inducedRules);

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -83,11 +83,12 @@ static void recordRelation(Term key,
8383

8484
assert(key.size() >= lhsRule.getRHS().size());
8585

86-
assert(lhsProperty.isProperty());
87-
assert(rhsProperty.isProperty());
88-
assert(lhsProperty.getKind() == rhsProperty.getKind() ||
86+
assert((lhsProperty.getKind() == Symbol::Kind::Layout &&
87+
rhsProperty.getKind() == Symbol::Kind::Layout) ||
8988
(lhsProperty.getKind() == Symbol::Kind::Superclass &&
90-
rhsProperty.getKind() == Symbol::Kind::Layout));
89+
rhsProperty.getKind() == Symbol::Kind::Layout) ||
90+
(lhsProperty.getKind() == Symbol::Kind::ConcreteType &&
91+
rhsProperty.getKind() == Symbol::Kind::Superclass));
9192

9293
if (debug) {
9394
llvm::dbgs() << "%% Recording relation: ";
@@ -132,16 +133,20 @@ static void recordConflict(Term key,
132133
unsigned existingRuleID,
133134
unsigned newRuleID,
134135
RewriteSystem &system) {
136+
auto &existingRule = system.getRule(existingRuleID);
137+
auto &newRule = system.getRule(newRuleID);
138+
139+
auto existingKind = existingRule.isPropertyRule()->getKind();
140+
auto newKind = newRule.isPropertyRule()->getKind();
141+
135142
// The GSB only dropped the new rule in the case of a conflicting
136143
// superclass requirement, so maintain that behavior here.
137-
auto &existingRule = system.getRule(existingRuleID);
138-
if (existingRule.isPropertyRule()->getKind() !=
139-
Symbol::Kind::Superclass) {
144+
if (existingKind != Symbol::Kind::Superclass &&
145+
existingKind == newKind) {
140146
if (existingRule.getRHS().size() == key.size())
141147
existingRule.markConflicting();
142148
}
143149

144-
auto &newRule = system.getRule(newRuleID);
145150
assert(newRule.getRHS().size() == key.size());
146151
newRule.markConflicting();
147152
}
@@ -546,10 +551,39 @@ void PropertyMap::addProperty(
546551
llvm_unreachable("Bad symbol kind");
547552
}
548553

554+
void PropertyMap::checkConcreteTypeRequirements(
555+
SmallVectorImpl<InducedRule> &inducedRules) {
556+
bool debug = Debug.contains(DebugFlags::ConcreteUnification);
557+
558+
for (auto *props : Entries) {
559+
if (props->ConcreteTypeRule && props->SuperclassRule) {
560+
auto concreteType = props->ConcreteType->getConcreteType();
561+
562+
// A rule (T.[concrete: C] => T) where C is a class type induces a rule
563+
// (T.[superclass: C] => T).
564+
if (concreteType->getClassOrBoundGenericClass()) {
565+
auto superclassSymbol = Symbol::forSuperclass(
566+
concreteType, props->ConcreteType->getSubstitutions(),
567+
Context);
568+
569+
recordRelation(props->getKey(), *props->ConcreteTypeRule,
570+
superclassSymbol, System,
571+
inducedRules, debug);
572+
573+
// Otherwise, we have a concrete vs superclass conflict.
574+
} else {
575+
recordConflict(props->getKey(),
576+
*props->ConcreteTypeRule,
577+
*props->SuperclassRule, System);
578+
}
579+
}
580+
}
581+
}
582+
549583
/// For each fully-concrete type, find the shortest term having that concrete type.
550584
/// This is later used by computeConstraintTermForTypeWitness().
551585
void PropertyMap::computeConcreteTypeInDomainMap() {
552-
for (const auto &props : Entries) {
586+
for (auto *props : Entries) {
553587
if (!props->isConcreteType())
554588
continue;
555589

@@ -575,7 +609,7 @@ void PropertyMap::computeConcreteTypeInDomainMap() {
575609

576610
void PropertyMap::concretizeNestedTypesFromConcreteParents(
577611
SmallVectorImpl<InducedRule> &inducedRules) {
578-
for (const auto &props : Entries) {
612+
for (auto *props : Entries) {
579613
if (props->getConformsTo().empty())
580614
continue;
581615

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-frontend -typecheck %s -debug-generic-signatures -requirement-machine-protocol-signatures=on 2>&1 | %FileCheck %s
2+
3+
class C {}
4+
5+
struct S {}
6+
7+
// CHECK-LABEL: superclass_and_concrete_requirement.(file).P1@
8+
// CHECK-NEXT: Requirement signature: <Self where Self.T == C>
9+
protocol P1 {
10+
associatedtype T where T : C, T == C
11+
}
12+
13+
// CHECK-LABEL: superclass_and_concrete_requirement.(file).P2@
14+
// CHECK-NEXT: Requirement signature: <Self where Self.T == S>
15+
protocol P2 {
16+
associatedtype T where T : C, T == S
17+
}
18+
19+
// CHECK-LABEL: superclass_and_concrete_requirement.(file).P3@
20+
// CHECK-NEXT: Requirement signature: <Self where Self.T == S>
21+
protocol P3 {
22+
associatedtype T where T == S, T : C
23+
}

0 commit comments

Comments
 (0)