Skip to content

Commit 6753530

Browse files
committed
RequirementMachine: Move implementation of StructuralRequirementsRequest and ProtocolDependenciesRequest to RequirementLowering.cpp
1 parent ff5d0e1 commit 6753530

File tree

2 files changed

+267
-258
lines changed

2 files changed

+267
-258
lines changed

lib/AST/RequirementMachine/RequirementLowering.cpp

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
#include "RequirementLowering.h"
2626
#include "swift/AST/ASTContext.h"
2727
#include "swift/AST/Decl.h"
28+
#include "swift/AST/ExistentialLayout.h"
2829
#include "swift/AST/Requirement.h"
30+
#include "swift/AST/TypeCheckRequests.h"
31+
#include "swift/AST/TypeMatcher.h"
32+
#include "swift/AST/TypeRepr.h"
2933
#include "llvm/ADT/SmallVector.h"
3034
#include "RewriteContext.h"
3135
#include "RewriteSystem.h"
@@ -35,6 +39,269 @@
3539
using namespace swift;
3640
using namespace rewriting;
3741

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+
}
85+
86+
/// Desugar a same-type requirement that possibly has concrete types on either
87+
/// side into a series of same-type and concrete-type requirements where the
88+
/// 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) {
92+
class Matcher : public TypeMatcher<Matcher> {
93+
SourceLoc loc;
94+
bool wasInferred;
95+
SmallVectorImpl<StructuralRequirement> &result;
96+
97+
public:
98+
Matcher(SourceLoc loc, bool wasInferred,
99+
SmallVectorImpl<StructuralRequirement> &result)
100+
: loc(loc), wasInferred(wasInferred), result(result) {}
101+
102+
bool mismatch(TypeBase *firstType, TypeBase *secondType,
103+
Type sugaredFirstType) {
104+
if (firstType->isTypeParameter() && secondType->isTypeParameter()) {
105+
result.push_back({Requirement(RequirementKind::SameType,
106+
firstType, secondType),
107+
loc, wasInferred});
108+
return true;
109+
}
110+
111+
if (firstType->isTypeParameter()) {
112+
result.push_back({Requirement(RequirementKind::SameType,
113+
firstType, secondType),
114+
loc, wasInferred});
115+
return true;
116+
}
117+
118+
if (secondType->isTypeParameter()) {
119+
result.push_back({Requirement(RequirementKind::SameType,
120+
secondType, firstType),
121+
loc, wasInferred});
122+
return true;
123+
}
124+
125+
// FIXME: Diagnose concrete type conflict
126+
return true;
127+
}
128+
} matcher(loc, wasInferred, result);
129+
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
133+
(void) matcher.match(lhs, rhs);
134+
}
135+
136+
static void inferRequirements(Type type, SourceLoc loc,
137+
SmallVectorImpl<StructuralRequirement> &result) {
138+
// FIXME: Implement
139+
}
140+
141+
static void addRequirement(Requirement req, RequirementRepr *reqRepr, bool infer,
142+
SmallVectorImpl<StructuralRequirement> &result) {
143+
auto firstType = req.getFirstType();
144+
if (infer) {
145+
auto firstLoc = (reqRepr ? reqRepr->getFirstTypeRepr()->getStartLoc()
146+
: SourceLoc());
147+
inferRequirements(firstType, firstLoc, result);
148+
}
149+
150+
auto loc = (reqRepr ? reqRepr->getSeparatorLoc() : SourceLoc());
151+
152+
switch (req.getKind()) {
153+
case RequirementKind::Superclass:
154+
case RequirementKind::Conformance: {
155+
if (!firstType->isTypeParameter()) {
156+
// FIXME: Warn about redundancy if not inferred, diagnose conflicts
157+
break;
158+
}
159+
160+
auto secondType = req.getSecondType();
161+
if (infer) {
162+
auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc()
163+
: SourceLoc());
164+
inferRequirements(secondType, secondLoc, result);
165+
}
166+
167+
addTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false,
168+
result);
169+
break;
170+
}
171+
172+
case RequirementKind::Layout:
173+
if (!firstType->isTypeParameter()) {
174+
// FIXME: Warn about redundancy if not inferred, diagnose conflicts
175+
break;
176+
}
177+
178+
result.push_back({req, loc, /*wasInferred=*/false});
179+
break;
180+
181+
case RequirementKind::SameType: {
182+
auto secondType = req.getSecondType();
183+
if (infer) {
184+
auto secondLoc = (reqRepr ? reqRepr->getSecondTypeRepr()->getStartLoc()
185+
: SourceLoc());
186+
inferRequirements(secondType, secondLoc, result);
187+
}
188+
189+
addSameTypeRequirement(firstType, secondType, loc, /*wasInferred=*/false,
190+
result);
191+
break;
192+
}
193+
}
194+
}
195+
196+
static void addInheritedRequirements(TypeDecl *decl, Type type, bool infer,
197+
SmallVectorImpl<StructuralRequirement> &result) {
198+
auto &ctx = decl->getASTContext();
199+
auto inheritedTypes = decl->getInherited();
200+
201+
for (unsigned index : indices(inheritedTypes)) {
202+
Type inheritedType
203+
= evaluateOrDefault(ctx.evaluator,
204+
InheritedTypeRequest{decl, index,
205+
TypeResolutionStage::Structural},
206+
Type());
207+
if (!inheritedType) continue;
208+
209+
auto *typeRepr = inheritedTypes[index].getTypeRepr();
210+
SourceLoc loc = (typeRepr ? typeRepr->getStartLoc() : SourceLoc());
211+
if (infer) {
212+
inferRequirements(inheritedType, loc, result);
213+
}
214+
215+
addTypeRequirement(type, inheritedType, loc, /*wasInferred=*/false,
216+
result);
217+
}
218+
}
219+
220+
ArrayRef<StructuralRequirement>
221+
StructuralRequirementsRequest::evaluate(Evaluator &evaluator,
222+
ProtocolDecl *proto) const {
223+
assert(!proto->hasLazyRequirementSignature());
224+
225+
SmallVector<StructuralRequirement, 4> result;
226+
227+
auto &ctx = proto->getASTContext();
228+
229+
auto selfTy = proto->getSelfInterfaceType();
230+
231+
addInheritedRequirements(proto, selfTy,
232+
/*infer=*/false, result);
233+
234+
// Add requirements from the protocol's own 'where' clause.
235+
WhereClauseOwner(proto).visitRequirements(TypeResolutionStage::Structural,
236+
[&](const Requirement &req, RequirementRepr *reqRepr) {
237+
addRequirement(req, reqRepr, /*infer=*/false, result);
238+
return false;
239+
});
240+
241+
if (proto->isObjC()) {
242+
// @objc protocols have an implicit AnyObject requirement on Self.
243+
auto layout = LayoutConstraint::getLayoutConstraint(
244+
LayoutConstraintKind::Class, ctx);
245+
result.push_back({Requirement(RequirementKind::Layout, selfTy, layout),
246+
proto->getLoc(), /*inferred=*/true});
247+
248+
// Remaining logic is not relevant to @objc protocols.
249+
return ctx.AllocateCopy(result);
250+
}
251+
252+
// Add requirements for each of the associated types.
253+
for (auto assocTypeDecl : proto->getAssociatedTypeMembers()) {
254+
// Add requirements placed directly on this associated type.
255+
auto assocType = assocTypeDecl->getDeclaredInterfaceType();
256+
addInheritedRequirements(assocTypeDecl, assocType, /*infer=*/false,
257+
result);
258+
259+
// Add requirements from this associated type's where clause.
260+
WhereClauseOwner(assocTypeDecl).visitRequirements(
261+
TypeResolutionStage::Structural,
262+
[&](const Requirement &req, RequirementRepr *reqRepr) {
263+
addRequirement(req, reqRepr, /*infer=*/false, result);
264+
return false;
265+
});
266+
}
267+
268+
return ctx.AllocateCopy(result);
269+
}
270+
271+
ArrayRef<ProtocolDecl *>
272+
ProtocolDependenciesRequest::evaluate(Evaluator &evaluator,
273+
ProtocolDecl *proto) const {
274+
auto &ctx = proto->getASTContext();
275+
SmallVector<ProtocolDecl *, 4> result;
276+
277+
// If we have a serialized requirement signature, deserialize it and
278+
// look at conformance requirements.
279+
//
280+
// FIXME: For now we just fall back to the GSB for all protocols
281+
// unless -requirement-machine-protocol-signatures=on is passed.
282+
if (proto->hasLazyRequirementSignature() ||
283+
(ctx.LangOpts.RequirementMachineProtocolSignatures
284+
== RequirementMachineMode::Disabled)) {
285+
for (auto req : proto->getRequirementSignature()) {
286+
if (req.getKind() == RequirementKind::Conformance) {
287+
result.push_back(req.getProtocolDecl());
288+
}
289+
}
290+
291+
return ctx.AllocateCopy(result);
292+
}
293+
294+
// Otherwise, we can't ask for the requirement signature, because
295+
// this request is used as part of *building* the requirement
296+
// signature. Look at the structural requirements instead.
297+
for (auto req : proto->getStructuralRequirements()) {
298+
if (req.req.getKind() == RequirementKind::Conformance)
299+
result.push_back(req.req.getProtocolDecl());
300+
}
301+
302+
return ctx.AllocateCopy(result);
303+
}
304+
38305
/// Given a concrete type that may contain type parameters in structural positions,
39306
/// collect all the structural type parameter components, and replace them all with
40307
/// fresh generic parameters. The fresh generic parameters all have a depth of 0,

0 commit comments

Comments
 (0)