Skip to content

Commit cd86924

Browse files
committed
RequirementMachine: Better simulation of GSB's 'connected components' malarkey
1 parent 77b8dfe commit cd86924

File tree

2 files changed

+122
-30
lines changed

2 files changed

+122
-30
lines changed

lib/AST/RequirementMachine/RequirementMachineRequests.cpp

Lines changed: 90 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,71 @@ STATISTIC(NumLazyRequirementSignaturesLoaded,
4040

4141
#undef DEBUG_TYPE
4242

43+
namespace {
44+
45+
/// Represents a set of types related by same-type requirements, and an
46+
/// optional concrete type requirement.
47+
struct ConnectedComponent {
48+
llvm::SmallVector<Type, 2> Members;
49+
Type ConcreteType;
50+
51+
void buildRequirements(Type subjectType, std::vector<Requirement> &reqs);
52+
};
53+
54+
/// Case 1: A set of rewrite rules of the form:
55+
///
56+
/// B => A
57+
/// C => A
58+
/// D => A
59+
///
60+
/// Become a series of same-type requirements
61+
///
62+
/// A == B, B == C, C == D
63+
///
64+
/// Case 2: A set of rewrite rules of the form:
65+
///
66+
/// A.[concrete: X] => A
67+
/// B => A
68+
/// C => A
69+
/// D => A
70+
///
71+
/// Become a series of same-type requirements
72+
///
73+
/// A == X, B == X, C == X, D == X
74+
void ConnectedComponent::buildRequirements(Type subjectType,
75+
std::vector<Requirement> &reqs) {
76+
std::sort(Members.begin(), Members.end(),
77+
[](Type first, Type second) -> bool {
78+
return compareDependentTypes(first, second) < 0;
79+
});
80+
81+
if (!ConcreteType) {
82+
for (auto constraintType : Members) {
83+
reqs.emplace_back(RequirementKind::SameType,
84+
subjectType, constraintType);
85+
subjectType = constraintType;
86+
}
87+
} else {
88+
reqs.emplace_back(RequirementKind::SameType,
89+
subjectType, ConcreteType);
90+
91+
for (auto constraintType : Members) {
92+
reqs.emplace_back(RequirementKind::SameType,
93+
constraintType, ConcreteType);
94+
}
95+
}
96+
}
97+
98+
} // end namespace
99+
43100
/// Convert a list of non-permanent, non-redundant rewrite rules into a minimal
44101
/// protocol requirement signature for \p proto. The requirements are sorted in
45102
/// canonical order, and same-type requirements are canonicalized.
46103
std::vector<Requirement>
47104
RequirementMachine::buildRequirementSignature(ArrayRef<unsigned> rules,
48105
const ProtocolDecl *proto) const {
49106
std::vector<Requirement> reqs;
50-
llvm::SmallDenseMap<TypeBase *, llvm::SmallVector<Type, 2>> sameTypeReqs;
107+
llvm::SmallDenseMap<TypeBase *, ConnectedComponent> sameTypeReqs;
51108

52109
auto genericParams = proto->getGenericSignature().getGenericParams();
53110
const auto &protos = System.getProtocols();
@@ -81,15 +138,18 @@ RequirementMachine::buildRequirementSignature(ArrayRef<unsigned> rules,
81138
protos));
82139
return;
83140

84-
case Symbol::Kind::ConcreteType:
85-
reqs.emplace_back(RequirementKind::SameType,
86-
subjectType,
87-
Context.getTypeFromSubstitutionSchema(
88-
prop->getConcreteType(),
89-
prop->getSubstitutions(),
90-
genericParams, MutableTerm(),
91-
protos));
141+
case Symbol::Kind::ConcreteType: {
142+
auto concreteType = Context.getTypeFromSubstitutionSchema(
143+
prop->getConcreteType(),
144+
prop->getSubstitutions(),
145+
genericParams, MutableTerm(),
146+
protos);
147+
148+
auto &component = sameTypeReqs[subjectType.getPointer()];
149+
assert(!component.ConcreteType);
150+
component.ConcreteType = concreteType;
92151
return;
152+
}
93153

94154
case Symbol::Kind::Name:
95155
case Symbol::Kind::AssociatedType:
@@ -104,41 +164,41 @@ RequirementMachine::buildRequirementSignature(ArrayRef<unsigned> rules,
104164
auto subjectType = Context.getTypeForTerm(rule.getRHS(), genericParams,
105165
protos);
106166

107-
sameTypeReqs[subjectType.getPointer()].push_back(constraintType);
167+
sameTypeReqs[subjectType.getPointer()].Members.push_back(constraintType);
108168
}
109169
};
110170

171+
if (getDebugOptions().contains(DebugFlags::Minimization)) {
172+
llvm::dbgs() << "Minimized rules:\n";
173+
}
174+
111175
// Build the list of requirements, storing same-type requirements off
112176
// to the side.
113177
for (unsigned ruleID : rules) {
114178
const auto &rule = System.getRule(ruleID);
179+
180+
if (getDebugOptions().contains(DebugFlags::Minimization)) {
181+
llvm::dbgs() << "- " << rule << "\n";
182+
}
183+
115184
createRequirementFromRule(rule);
116185
}
117186

118-
// A set of rewrite rules of the form:
119-
//
120-
// B => A
121-
// C => A
122-
// D => A
123-
//
124-
// Become a series of same-type requirements
125-
//
126-
// A == B, B == C, C == D
127-
//
187+
// Now, convert each connected component into a series of same-type
188+
// requirements.
128189
for (auto &pair : sameTypeReqs) {
129-
std::sort(pair.second.begin(), pair.second.end(),
130-
[](Type first, Type second) -> bool {
131-
return compareDependentTypes(first, second) < 0;
132-
});
133-
134-
Type subjectType(pair.first);
135-
for (auto constraintType : pair.second) {
136-
reqs.emplace_back(RequirementKind::SameType, subjectType, constraintType);
137-
subjectType = constraintType;
190+
pair.second.buildRequirements(pair.first, reqs);
191+
}
192+
193+
if (getDebugOptions().contains(DebugFlags::Minimization)) {
194+
llvm::dbgs() << "Requirements:\n";
195+
for (const auto &req : reqs) {
196+
req.dump(llvm::dbgs());
197+
llvm::dbgs() << "\n";
138198
}
139199
}
140200

141-
// Sort the requirements in canonical order.
201+
// Finally, sort the requirements in canonical order.
142202
std::sort(reqs.begin(), reqs.end(),
143203
[](const Requirement &lhs, const Requirement &rhs) -> bool {
144204
return lhs.compare(rhs) < 0;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend -typecheck -debug-generic-signatures -requirement-machine-protocol-signatures=on %s 2>&1 | %FileCheck %s
2+
3+
protocol P {
4+
associatedtype T
5+
}
6+
7+
protocol Base {
8+
associatedtype A
9+
associatedtype B
10+
associatedtype C
11+
associatedtype D : P where B == D.T
12+
}
13+
14+
// CHECK-LABEL: connected_components_concrete.(file).Derived1@
15+
// CHECK-LABEL: Requirement signature: <Self where Self : Base, Self.A == Int, Self.B == Int, Self.C == Int>
16+
protocol Derived1 : Base where A == B, A == C, A == Int {}
17+
18+
// CHECK-LABEL: connected_components_concrete.(file).Derived2@
19+
// CHECK-LABEL: Requirement signature: <Self where Self : Base, Self.A == Int, Self.B == Int, Self.C == Int>
20+
protocol Derived2 : Base where A == D.T, A == C, B == Int {}
21+
22+
// CHECK-LABEL: connected_components_concrete.(file).Derived3@
23+
// CHECK-LABEL: Requirement signature: <Self where Self : Base, Self.A == Int, Self.B == Int, Self.C == Int>
24+
protocol Derived3 : Base where A == B, B == C, A == Int {}
25+
26+
// CHECK-LABEL: connected_components_concrete.(file).Derived4@
27+
// CHECK-LABEL: Requirement signature: <Self where Self : Base, Self.A == Int, Self.B == Int, Self.C == Int>
28+
protocol Derived4 : Base where A == Int, B == Int, C == Int {}
29+
30+
// CHECK-LABEL: connected_components_concrete.(file).Derived5@
31+
// CHECK-LABEL: Requirement signature: <Self where Self : Base, Self.A == Int, Self.B == Int, Self.C == Int>
32+
protocol Derived5 : Base where A == Int, D.T == Int, C == Int {}

0 commit comments

Comments
 (0)