@@ -37,6 +37,10 @@ struct RewriteSystemBuilder {
37
37
ProtocolGraph Protocols;
38
38
std::vector<std::pair<MutableTerm, MutableTerm>> Rules;
39
39
40
+ CanType getConcreteSubstitutionSchema (CanType concreteType,
41
+ const ProtocolDecl *proto,
42
+ SmallVector<Term> &result);
43
+
40
44
RewriteSystemBuilder (RewriteContext &ctx, bool debug)
41
45
: Context(ctx), Debug(debug) {}
42
46
void addGenericSignature (CanGenericSignature sig);
@@ -48,6 +52,32 @@ struct RewriteSystemBuilder {
48
52
49
53
} // end namespace
50
54
55
+ // / Given a concrete type that may contain type parameters in structural positions,
56
+ // / collect all the structural type parameter components, and replace them all with
57
+ // / fresh generic parameters. The fresh generic parameters all have a depth of 0,
58
+ // / and the index is an index into the 'result' array.
59
+ // /
60
+ // / For example, given the concrete type Foo<X.Y, Array<Z>>, this produces the
61
+ // / result type Foo<τ_0_0, Array<τ_0_1>>, with result array {X.Y, Z}.
62
+ CanType
63
+ RewriteSystemBuilder::getConcreteSubstitutionSchema (CanType concreteType,
64
+ const ProtocolDecl *proto,
65
+ SmallVector<Term> &result) {
66
+ if (!concreteType->hasTypeParameter ())
67
+ return concreteType;
68
+
69
+ return CanType (concreteType.transformRec (
70
+ [&](Type t) -> Optional<Type> {
71
+ if (!t->isTypeParameter ())
72
+ return None;
73
+
74
+ unsigned index = result.size ();
75
+ result.push_back (Context.getTermForType (CanType (t), proto));
76
+
77
+ return CanGenericTypeParamType::get (/* depth=*/ 0 , index, Context.getASTContext ());
78
+ }));
79
+ }
80
+
51
81
void RewriteSystemBuilder::addGenericSignature (CanGenericSignature sig) {
52
82
// Collect all protocols transitively referenced from the generic signature's
53
83
// requirements.
@@ -115,8 +145,12 @@ void RewriteSystemBuilder::addRequirement(const Requirement &req,
115
145
llvm::dbgs () << " \n " ;
116
146
}
117
147
148
+ // Compute the left hand side.
118
149
auto subjectType = CanType (req.getFirstType ());
119
- auto subjectTerm = Context.getTermForType (subjectType, proto);
150
+ auto subjectTerm = Context.getMutableTermForType (subjectType, proto);
151
+
152
+ // Compute the right hand side.
153
+ MutableTerm constraintTerm;
120
154
121
155
switch (req.getKind ()) {
122
156
case RequirementKind::Conformance: {
@@ -127,55 +161,72 @@ void RewriteSystemBuilder::addRequirement(const Requirement &req,
127
161
// Intuitively, this means "any type ending with T conforms to P".
128
162
auto *proto = req.getProtocolDecl ();
129
163
130
- auto constraintTerm = subjectTerm;
164
+ constraintTerm = subjectTerm;
131
165
constraintTerm.add (Atom::forProtocol (proto, Context));
132
-
133
- Rules.emplace_back (subjectTerm, constraintTerm);
134
166
break ;
135
167
}
136
168
137
- case RequirementKind::Superclass:
138
- // FIXME: Implement
169
+ case RequirementKind::Superclass: {
170
+ // A superclass requirement T : C<X, Y> becomes a rewrite rule
171
+ //
172
+ // T.[superclass: C<X, Y>] => T
173
+ auto otherType = CanType (req.getSecondType ());
174
+
175
+ SmallVector<Term> substitutions;
176
+ otherType = getConcreteSubstitutionSchema (otherType, proto,
177
+ substitutions);
178
+
179
+ constraintTerm = subjectTerm;
180
+ constraintTerm.add (Atom::forSuperclass (otherType, substitutions,
181
+ Context));
139
182
break ;
183
+ }
140
184
141
185
case RequirementKind::Layout: {
142
186
// A layout requirement T : L becomes a rewrite rule
143
187
//
144
188
// T.[L] == T
145
- auto constraintTerm = subjectTerm;
189
+ constraintTerm = subjectTerm;
146
190
constraintTerm.add (Atom::forLayout (req.getLayoutConstraint (),
147
191
Context));
148
-
149
- Rules.emplace_back (subjectTerm, constraintTerm);
150
192
break ;
151
193
}
152
194
153
195
case RequirementKind::SameType: {
154
- // A same-type requirement T == U becomes a rewrite rule
155
- //
156
- // T == U
157
196
auto otherType = CanType (req.getSecondType ());
158
197
159
- // FIXME: Handle concrete types
160
- if (!otherType->isTypeParameter ())
198
+ if (!otherType->isTypeParameter ()) {
199
+ // A concrete same-type requirement T == C<X, Y> becomes a
200
+ // rewrite rule
201
+ //
202
+ // T.[concrete: C<X, Y>] => T
203
+ SmallVector<Term> substitutions;
204
+ otherType = getConcreteSubstitutionSchema (otherType, proto,
205
+ substitutions);
206
+
207
+ constraintTerm = subjectTerm;
208
+ constraintTerm.add (Atom::forConcreteType (otherType, substitutions,
209
+ Context));
161
210
break ;
211
+ }
162
212
163
- auto otherTerm = Context.getTermForType (otherType, proto);
164
-
165
- Rules.emplace_back (subjectTerm, otherTerm);
213
+ constraintTerm = Context.getMutableTermForType (otherType, proto);
166
214
break ;
167
215
}
168
216
}
217
+
218
+ Rules.emplace_back (subjectTerm, constraintTerm);
169
219
}
170
220
221
+
171
222
// / We use the PIMPL pattern to avoid creeping header dependencies.
172
223
struct RequirementMachine ::Implementation {
173
224
RewriteContext Context;
174
225
RewriteSystem System;
175
226
bool Complete = false ;
176
227
177
- Implementation (ASTContext &ctx)
178
- : Context(ctx.Stats ), System(Context) {}
228
+ explicit Implementation (ASTContext &ctx)
229
+ : Context(ctx), System(Context) {}
179
230
};
180
231
181
232
RequirementMachine::RequirementMachine (ASTContext &ctx) : Context(ctx) {
0 commit comments