@@ -31,6 +31,17 @@ namespace swift {
31
31
32
32
namespace rewriting {
33
33
34
+ // / The most primitive term in the rewrite system.
35
+ // /
36
+ // / enum Atom {
37
+ // / case name(Identifier)
38
+ // / case protocol(Protocol)
39
+ // / case type([Protocol], Identifier)
40
+ // / case genericParam(index: Int, depth: Int)
41
+ // / case layout(LayoutConstraint)
42
+ // / }
43
+ // /
44
+ // / Out-of-line methods are documented in RewriteSystem.cpp.
34
45
class Atom final {
35
46
using Storage = llvm::PointerUnion<Identifier,
36
47
GenericTypeParamType *,
@@ -47,42 +58,70 @@ class Atom final {
47
58
}
48
59
49
60
public:
61
+ // / Creates a new name atom.
50
62
static Atom forName (Identifier name) {
51
63
return Atom ({}, name);
52
64
}
53
65
66
+ // / Creates a new protocol atom.
54
67
static Atom forProtocol (const ProtocolDecl *proto) {
55
68
return Atom ({proto}, Storage ());
56
69
}
57
70
71
+ // / Creates a new associated type atom for a single protocol.
58
72
static Atom forAssociatedType (const ProtocolDecl *proto,
59
73
Identifier name) {
60
74
assert (proto != nullptr );
61
75
return Atom ({proto}, name);
62
76
}
63
77
78
+ // / Creates a merged associated type atom to represent a nested
79
+ // / type that conforms to multiple protocols, all of which have
80
+ // / an associated type with the same name.
64
81
static Atom forAssociatedType (
65
82
llvm::TinyPtrVector<const ProtocolDecl *>protos,
66
83
Identifier name) {
67
84
assert (!protos.empty ());
68
85
return Atom (protos, name);
69
86
}
70
87
88
+ // / Creates a generic parameter atom, representing a generic
89
+ // / parameter in the top-level generic signature from which the
90
+ // / rewrite system is built.
71
91
static Atom forGenericParam (GenericTypeParamType *param) {
72
92
assert (param->isCanonical ());
73
93
return Atom ({}, param);
74
94
}
75
95
96
+ // / Creates a layout atom, representing a layout constraint.
76
97
static Atom forLayout (LayoutConstraint layout) {
77
98
assert (layout->isKnownLayout ());
78
99
return Atom ({}, layout);
79
100
}
80
101
81
102
enum class Kind : uint8_t {
103
+ // / An associated type [P:T] or [P&Q&...:T]. The parent term
104
+ // / must be known to conform to P (or P, Q, ...).
82
105
AssociatedType,
106
+
107
+ // / A generic parameter, uniquely identified by depth and
108
+ // / index. Can only appear at the beginning of a term, where
109
+ // / it represents a generic parameter of the top-level generic
110
+ // / signature.
83
111
GenericParam,
112
+
113
+ // / An unbound identifier name.
84
114
Name,
115
+
116
+ // / When appearing at the start of a term, represents a nested
117
+ // / type of a protocol 'Self' type.
118
+ // /
119
+ // / When appearing at the end of a term, represents that the
120
+ // / term conforms to the protocol.
85
121
Protocol,
122
+
123
+ // / When appearring at the end of a term, represents that the
124
+ // / term conforms to the layout.
86
125
Layout
87
126
};
88
127
@@ -111,30 +150,37 @@ class Atom final {
111
150
llvm_unreachable (" Bad term rewriting atom" );
112
151
}
113
152
153
+ // / Get the identifier associated with an unbound name atom or an
154
+ // / associated type atom.
114
155
Identifier getName () const {
115
156
assert (getKind () == Kind::Name ||
116
157
getKind () == Kind::AssociatedType);
117
158
return Value.get <Identifier>();
118
159
}
119
160
161
+ // / Get the single protocol declaration associate with a protocol atom.
120
162
const ProtocolDecl *getProtocol () const {
121
163
assert (getKind () == Kind::Protocol);
122
164
assert (Protos.size () == 1 );
123
165
return Protos.front ();
124
166
}
125
167
168
+ // / Get the list of protocols associated with a protocol or associated
169
+ // / type atom.
126
170
llvm::TinyPtrVector<const ProtocolDecl *> getProtocols () const {
127
171
assert (getKind () == Kind::Protocol ||
128
172
getKind () == Kind::AssociatedType);
129
173
assert (!Protos.empty ());
130
174
return Protos;
131
175
}
132
176
177
+ // / Get the generic parameter associated with a generic parameter atom.
133
178
GenericTypeParamType *getGenericParam () const {
134
179
assert (getKind () == Kind::GenericParam);
135
180
return Value.get <GenericTypeParamType *>();
136
181
}
137
182
183
+ // / Get the layout constraint associated with a layout constraint atom.
138
184
LayoutConstraint getLayoutConstraint () const {
139
185
assert (getKind () == Kind::Layout);
140
186
return Value.get <LayoutConstraint>();
@@ -156,6 +202,14 @@ class Atom final {
156
202
}
157
203
};
158
204
205
+ // / A term is a sequence of one or more atoms.
206
+ // /
207
+ // / The first atom in the term must be a protocol, generic parameter, or
208
+ // / associated type atom.
209
+ // /
210
+ // / A layout constraint atom must only appear at the end of a term.
211
+ // /
212
+ // / Out-of-line methods are documented in RewriteSystem.cpp.
159
213
class Term final {
160
214
llvm::SmallVector<Atom, 3 > Atoms;
161
215
@@ -202,6 +256,7 @@ class Term final {
202
256
203
257
decltype (Atoms)::iterator findSubTerm (const Term &other);
204
258
259
+ // / Returns true if this term contains, or is equal to, \p other.
205
260
bool containsSubTerm (const Term &other) const {
206
261
return findSubTerm (other) != end ();
207
262
}
@@ -213,6 +268,11 @@ class Term final {
213
268
void dump (llvm::raw_ostream &out) const ;
214
269
};
215
270
271
+ // / A rewrite rule that replaces occurrences of LHS with RHS.
272
+ // /
273
+ // / LHS must be greater than RHS in the linear order over terms.
274
+ // /
275
+ // / Out-of-line methods are documented in RewriteSystem.cpp.
216
276
class Rule final {
217
277
Term LHS;
218
278
Term RHS;
@@ -238,19 +298,27 @@ class Rule final {
238
298
return LHS.containsSubTerm (other.LHS );
239
299
}
240
300
301
+ // / Returns if the rule was deleted.
241
302
bool isDeleted () const {
242
303
return deleted;
243
304
}
244
305
306
+ // / Deletes the rule, which removes it from consideration in term
307
+ // / simplification and completion. Deleted rules are simply marked as
308
+ // / such instead of being physically removed from the rules vector
309
+ // / in the rewrite system, to ensure that indices remain valid across
310
+ // / deletion.
245
311
void markDeleted () {
246
312
assert (!deleted);
247
313
deleted = true ;
248
314
}
249
315
316
+ // / Returns the length of the left hand side.
250
317
unsigned getDepth () const {
251
318
return LHS.size ();
252
319
}
253
320
321
+ // / Partial order on rules orders rules by their left hand side.
254
322
int compare (const Rule &other,
255
323
const ProtocolGraph &protos) const {
256
324
return LHS.compare (other.LHS , protos);
@@ -259,12 +327,35 @@ class Rule final {
259
327
void dump (llvm::raw_ostream &out) const ;
260
328
};
261
329
330
+ // / A term rewrite system for working with types in a generic signature.
331
+ // /
332
+ // / Out-of-line methods are documented in RewriteSystem.cpp.
262
333
class RewriteSystem final {
334
+ // / The rules added so far, including rules from our client, as well
335
+ // / as rules introduced by the completion procedure.
263
336
std::vector<Rule> Rules;
337
+
338
+ // / The graph of all protocols transitively referenced via our set of
339
+ // / rewrite rules, used for the linear order on atoms.
264
340
ProtocolGraph Protos;
341
+
342
+ // / A list of pending terms for the associated type merging completion
343
+ // / heuristic.
344
+ // /
345
+ // / The pair (lhs, rhs) satisfies the following conditions:
346
+ // / - lhs > rhs
347
+ // / - all atoms but the last are pair-wise equal in lhs and rhs
348
+ // / - the last atom in both lhs and rhs is an associated type atom
349
+ // / - the last atom in both lhs and rhs has the same name
350
+ // /
351
+ // / See RewriteSystem::processMergedAssociatedTypes() for details.
265
352
std::vector<std::pair<Term, Term>> MergedAssociatedTypes;
353
+
354
+ // / A list of pending pairs for checking overlap in the completion
355
+ // / procedure.
266
356
std::deque<std::pair<unsigned , unsigned >> Worklist;
267
357
358
+ // / Set these to true to enable debugging output.
268
359
unsigned DebugSimplify : 1 ;
269
360
unsigned DebugAdd : 1 ;
270
361
unsigned DebugMerge : 1 ;
@@ -291,8 +382,14 @@ class RewriteSystem final {
291
382
bool simplify (Term &term) const ;
292
383
293
384
enum class CompletionResult {
385
+ // / Confluent completion was computed successfully.
294
386
Success,
387
+
388
+ // / Maximum number of iterations reached.
295
389
MaxIterations,
390
+
391
+ // / Completion produced a rewrite rule whose left hand side has a length
392
+ // / exceeding the limit.
296
393
MaxDepth
297
394
};
298
395
0 commit comments