Skip to content

Commit df8ce67

Browse files
committed
RequirementMachine: Refactor requirement lowering
1 parent 6753530 commit df8ce67

File tree

2 files changed

+180
-94
lines changed

2 files changed

+180
-94
lines changed

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 176 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -39,107 +39,183 @@
3939
using namespace swift;
4040
using namespace rewriting;
4141

42-
/// Desugar a protocol conformance requirement by splitting up protocol
43-
/// compositions on the right hand side until conformance and superclass
44-
/// requirements.
45-
static void addTypeRequirement(Type subjectType, Type constraintType,
46-
SourceLoc loc, bool wasInferred,
47-
SmallVectorImpl<StructuralRequirement> &result) {
48-
// Check whether we have a reasonable constraint type at all.
49-
if (!constraintType->isExistentialType() &&
50-
!constraintType->getClassOrBoundGenericClass()) {
51-
// FIXME: Diagnose
52-
return;
53-
}
54-
55-
// Protocol requirements.
56-
if (constraintType->isExistentialType()) {
57-
auto layout = constraintType->getExistentialLayout();
58-
59-
if (auto layoutConstraint = layout.getLayoutConstraint()) {
60-
result.push_back({
61-
Requirement(RequirementKind::Layout, subjectType, layoutConstraint),
62-
loc, wasInferred});
63-
}
64-
65-
if (auto superclass = layout.explicitSuperclass) {
66-
result.push_back({
67-
Requirement(RequirementKind::Superclass, subjectType, superclass),
68-
loc, wasInferred});
69-
}
70-
71-
for (auto *proto : layout.getProtocols()) {
72-
result.push_back({
73-
Requirement(RequirementKind::Conformance, subjectType, proto),
74-
loc, wasInferred});
75-
}
76-
77-
return;
78-
}
79-
80-
// Superclass constraint.
81-
result.push_back({
82-
Requirement(RequirementKind::Superclass, subjectType, constraintType),
83-
loc, wasInferred});
84-
}
42+
//
43+
// Requirement desugaring -- used in two places:
44+
//
45+
// 1) AbstractGenericSignatureRequest, where the added requirements might have
46+
// substitutions applied.
47+
//
48+
// 2) StructuralRequirementsRequest, which performs further processing to wrap
49+
// desugared requirements with source location information.
50+
//
8551

8652
/// Desugar a same-type requirement that possibly has concrete types on either
8753
/// side into a series of same-type and concrete-type requirements where the
8854
/// left hand side is always a type parameter.
89-
static void addSameTypeRequirement(Type lhs, Type rhs,
90-
SourceLoc loc, bool wasInferred,
91-
SmallVectorImpl<StructuralRequirement> &result) {
55+
static void desugarSameTypeRequirement(Type lhs, Type rhs,
56+
SmallVectorImpl<Requirement> &result) {
9257
class Matcher : public TypeMatcher<Matcher> {
93-
SourceLoc loc;
94-
bool wasInferred;
95-
SmallVectorImpl<StructuralRequirement> &result;
58+
SmallVectorImpl<Requirement> &result;
9659

9760
public:
98-
Matcher(SourceLoc loc, bool wasInferred,
99-
SmallVectorImpl<StructuralRequirement> &result)
100-
: loc(loc), wasInferred(wasInferred), result(result) {}
61+
explicit Matcher(SmallVectorImpl<Requirement> &result)
62+
: result(result) {}
10163

10264
bool mismatch(TypeBase *firstType, TypeBase *secondType,
10365
Type sugaredFirstType) {
10466
if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
105-
result.push_back({Requirement(RequirementKind::SameType,
106-
firstType, secondType),
107-
loc, wasInferred});
67+
result.emplace_back(RequirementKind::SameType,
68+
firstType, secondType);
10869
return true;
10970
}
11071

11172
if (firstType->isTypeParameter()) {
112-
result.push_back({Requirement(RequirementKind::SameType,
113-
firstType, secondType),
114-
loc, wasInferred});
73+
result.emplace_back(RequirementKind::SameType,
74+
firstType, secondType);
11575
return true;
11676
}
11777

11878
if (secondType->isTypeParameter()) {
119-
result.push_back({Requirement(RequirementKind::SameType,
120-
secondType, firstType),
121-
loc, wasInferred});
79+
result.emplace_back(RequirementKind::SameType,
80+
secondType, firstType);
12281
return true;
12382
}
12483

125-
// FIXME: Diagnose concrete type conflict
84+
// FIXME: Record concrete type conflict, diagnose upstream
12685
return true;
12786
}
128-
} matcher(loc, wasInferred, result);
87+
} matcher(result);
12988

130-
// FIXME: If both sides concrete and was not inferred, diagnose redundancy
131-
// FIXME: If both sides are equal as type parameters and not inferred,
132-
// diagnose redundancy
89+
// FIXME: Record redundancy and diagnose upstream
13390
(void) matcher.match(lhs, rhs);
13491
}
13592

93+
static void desugarSuperclassRequirement(Type subjectType,
94+
Type constraintType,
95+
SmallVectorImpl<Requirement> &result) {
96+
if (!subjectType->isTypeParameter()) {
97+
// FIXME: Perform unification, diagnose redundancy or conflict upstream
98+
return;
99+
}
100+
101+
result.emplace_back(RequirementKind::Superclass, subjectType, constraintType);
102+
}
103+
104+
static void desugarLayoutRequirement(Type subjectType,
105+
LayoutConstraint layout,
106+
SmallVectorImpl<Requirement> &result) {
107+
if (!subjectType->isTypeParameter()) {
108+
// FIXME: Diagnose redundancy or conflict upstream
109+
return;
110+
}
111+
112+
result.emplace_back(RequirementKind::Layout, subjectType, layout);
113+
}
114+
115+
/// Desugar a protocol conformance requirement by splitting up protocol
116+
/// compositions on the right hand side into conformance and superclass
117+
/// requirements.
118+
static void desugarConformanceRequirement(Type subjectType, Type constraintType,
119+
SmallVectorImpl<Requirement> &result) {
120+
// Fast path.
121+
if (constraintType->is<ProtocolType>()) {
122+
if (!subjectType->isTypeParameter()) {
123+
// FIXME: Check conformance, diagnose redundancy or conflict upstream
124+
return;
125+
}
126+
127+
result.emplace_back(RequirementKind::Conformance, subjectType,
128+
constraintType);
129+
return;
130+
}
131+
132+
auto layout = constraintType->getExistentialLayout();
133+
134+
if (auto layoutConstraint = layout.getLayoutConstraint())
135+
desugarLayoutRequirement(subjectType, layoutConstraint, result);
136+
137+
if (auto superclass = layout.explicitSuperclass)
138+
desugarSuperclassRequirement(subjectType, superclass, result);
139+
140+
for (auto *proto : layout.getProtocols()) {
141+
if (!subjectType->isTypeParameter()) {
142+
// FIXME: Check conformance, diagnose redundancy or conflict upstream
143+
return;
144+
}
145+
146+
result.emplace_back(RequirementKind::Conformance, subjectType,
147+
proto);
148+
}
149+
}
150+
151+
/// Convert a requirement where the subject type might not be a type parameter,
152+
/// or the constraint type in the conformance requirement might be a protocol
153+
/// composition, into zero or more "proper" requirements which can then be
154+
/// converted into rewrite rules by the RuleBuilder.
155+
void
156+
swift::rewriting::desugarRequirement(Requirement req,
157+
SmallVectorImpl<Requirement> &result) {
158+
auto firstType = req.getFirstType();
159+
160+
switch (req.getKind()) {
161+
case RequirementKind::Conformance:
162+
desugarConformanceRequirement(firstType, req.getSecondType(), result);
163+
break;
164+
165+
case RequirementKind::Superclass:
166+
desugarSuperclassRequirement(firstType, req.getSecondType(), result);
167+
break;
168+
169+
case RequirementKind::Layout:
170+
desugarLayoutRequirement(firstType, req.getLayoutConstraint(), result);
171+
break;
172+
173+
case RequirementKind::SameType:
174+
desugarSameTypeRequirement(firstType, req.getSecondType(), result);
175+
break;
176+
}
177+
}
178+
179+
//
180+
// StructuralRequirementsRequest computation.
181+
//
182+
// This realizes RequirementReprs into Requirements, desugars them using the
183+
// above, performs requirement inference, and wraps them with source location
184+
// information.
185+
//
186+
187+
static void realizeTypeRequirement(Type subjectType, Type constraintType,
188+
SourceLoc loc, bool wasInferred,
189+
SmallVectorImpl<StructuralRequirement> &result) {
190+
// Check whether we have a reasonable constraint type at all.
191+
if (!constraintType->isExistentialType() &&
192+
!constraintType->getClassOrBoundGenericClass()) {
193+
// FIXME: Diagnose
194+
return;
195+
}
196+
197+
SmallVector<Requirement, 2> reqs;
198+
199+
if (constraintType->isExistentialType()) {
200+
// Handle conformance requirements.
201+
desugarConformanceRequirement(subjectType, constraintType, reqs);
202+
} else {
203+
// Handle superclass requirements.
204+
desugarSuperclassRequirement(subjectType, constraintType, reqs);
205+
}
206+
207+
// Add source location information.
208+
for (auto req : reqs)
209+
result.push_back({req, loc, wasInferred});
210+
}
211+
136212
static void inferRequirements(Type type, SourceLoc loc,
137213
SmallVectorImpl<StructuralRequirement> &result) {
138214
// FIXME: Implement
139215
}
140216

141-
static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer,
142-
SmallVectorImpl<StructuralRequirement> &result) {
217+
static void realizeRequirement(Requirement req, RequirementRepr *reqRepr, bool infer,
218+
SmallVectorImpl<StructuralRequirement> &result) {
143219
auto firstType = req.getFirstType();
144220
if (infer) {
145221
auto firstLoc = (reqRepr ? reqRepr->getFirstTypeRepr()->getStartLoc()
@@ -152,31 +228,27 @@ static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer
152228
switch (req.getKind()) {
153229
case RequirementKind::Superclass:
154230
case RequirementKind::Conformance: {
155-
if (!firstType->isTypeParameter()) {
156-
// FIXME: Warn about redundancy if not inferred, diagnose conflicts
157-
break;
158-
}
159-
160231
auto secondType = req.getSecondType();
161232
if (infer) {
162233
auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc()
163234
: SourceLoc());
164235
inferRequirements(secondType, secondLoc, result);
165236
}
166237

167-
addTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false,
168-
result);
238+
realizeTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false,
239+
result);
169240
break;
170241
}
171242

172-
case RequirementKind::Layout:
173-
if (!firstType->isTypeParameter()) {
174-
// FIXME: Warn about redundancy if not inferred, diagnose conflicts
175-
break;
176-
}
243+
case RequirementKind::Layout: {
244+
SmallVector<Requirement, 2> reqs;
245+
desugarLayoutRequirement(firstType, req.getLayoutConstraint(), reqs);
246+
247+
for (auto req : reqs)
248+
result.push_back({req, loc, /*wasInferred=*/false});
177249

178-
result.push_back({req, loc, /*wasInferred=*/false});
179250
break;
251+
}
180252

181253
case RequirementKind::SameType: {
182254
auto secondType = req.getSecondType();
@@ -186,15 +258,18 @@ static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer
186258
inferRequirements(secondType, secondLoc, result);
187259
}
188260

189-
addSameTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false,
190-
result);
261+
SmallVector<Requirement, 2> reqs;
262+
desugarSameTypeRequirement(req.getFirstType(), secondType, reqs);
263+
264+
for (auto req : reqs)
265+
result.push_back({req, loc, /*wasInferred=*/false});
191266
break;
192267
}
193268
}
194269
}
195270

196-
static void addInheritedRequirements(TypeDecl *decl, Type type, bool infer,
197-
SmallVectorImpl<StructuralRequirement> &result) {
271+
static void realizeInheritedRequirements(TypeDecl *decl, Type type, bool infer,
272+
SmallVectorImpl<StructuralRequirement> &result) {
198273
auto &ctx = decl->getASTContext();
199274
auto inheritedTypes = decl->getInherited();
200275

@@ -212,8 +287,8 @@ static void addInheritedRequirements(TypeDecl *decl, Type type, bool infer,
212287
inferRequirements(inheritedType, loc, result);
213288
}
214289

215-
addTypeRequirement(type, inheritedType, loc, /*wasInferred=*/false,
216-
result);
290+
realizeTypeRequirement(type, inheritedType, loc, /*wasInferred=*/false,
291+
result);
217292
}
218293
}
219294

@@ -228,13 +303,13 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
228303

229304
auto selfTy = proto->getSelfInterfaceType();
230305

231-
addInheritedRequirements(proto, selfTy,
232-
/*infer=*/false, result);
306+
realizeInheritedRequirements(proto, selfTy,
307+
/*infer=*/false, result);
233308

234309
// Add requirements from the protocol's own 'where' clause.
235310
WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural,
236311
[&](const Requirement &req, RequirementRepr *reqRepr) {
237-
addRequirement(req, reqRepr, /*infer=*/false, result);
312+
realizeRequirement(req, reqRepr, /*infer=*/false, result);
238313
return false;
239314
});
240315

@@ -253,14 +328,14 @@ StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
253328
for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) {
254329
// Add requirements placed directly on this associated type.
255330
auto assocType = assocTypeDecl->getDeclaredInterfaceType();
256-
addInheritedRequirements(assocTypeDecl, assocType, /*infer=*/false,
257-
result);
331+
realizeInheritedRequirements(assocTypeDecl, assocType, /*infer=*/false,
332+
result);
258333

259334
// Add requirements from this associated type's where clause.
260335
WhereClauseOwner(assocTypeDecl).visitRequirements(
261336
TypeResolutionStage::Structural,
262337
[&](const Requirement &req, RequirementRepr *reqRepr) {
263-
addRequirement(req, reqRepr, /*infer=*/false, result);
338+
realizeRequirement(req, reqRepr, /*infer=*/false, result);
264339
return false;
265340
});
266341
}
@@ -302,6 +377,10 @@ ProtocolDependenciesRequest::evaluate(Evaluator &evaluator,
302377
return ctx.AllocateCopy(result);
303378
}
304379

380+
//
381+
// Building rewrite rules from desugared requirements.
382+
//
383+
305384
/// Given a concrete type that may contain type parameters in structural positions,
306385
/// collect all the structural type parameter components, and replace them all with
307386
/// fresh generic parameters. The fresh generic parameters all have a depth of 0,
@@ -556,8 +635,11 @@ void RuleBuilder::collectRulesFromReferencedProtocols() {
556635
// we can trigger the computation of the requirement signatures of the
557636
// next component recursively.
558637
if (ProtocolMap[proto]) {
559-
for (auto req : proto->getStructuralRequirements())
638+
for (auto req : proto->getStructuralRequirements()) {
639+
// FIXME: Keep source location information around for redundancy
640+
// diagnostics.
560641
addRequirement(req.req.getCanonical(), proto);
642+
}
561643
} else {
562644
for (auto req : proto->getRequirementSignature())
563645
addRequirement(req.getCanonical(), proto);

0 commit comments

Comments
 (0)