|
12 | 12 |
|
13 | 13 | #include "swift/AST/Decl.h"
|
14 | 14 | #include "swift/AST/Types.h"
|
15 |
| -#include "swift/AST/TypeWalker.h" |
16 |
| -#include "llvm/ADT/FoldingSet.h" |
17 | 15 | #include "llvm/Support/raw_ostream.h"
|
18 | 16 | #include <algorithm>
|
19 | 17 | #include <vector>
|
20 | 18 | #include "RewriteContext.h"
|
| 19 | +#include "RewriteLoop.h" |
21 | 20 | #include "RewriteSystem.h"
|
| 21 | +#include "Rule.h" |
| 22 | +#include "Trie.h" |
22 | 23 |
|
23 | 24 | using namespace swift;
|
24 | 25 | using namespace rewriting;
|
25 | 26 |
|
26 |
| -/// If this is a rule of the form T.[p] => T where [p] is a property symbol, |
27 |
| -/// returns the symbol. Otherwise, returns None. |
28 |
| -/// |
29 |
| -/// Note that this is meant to be used with a simplified rewrite system, |
30 |
| -/// where the right hand sides of rules are canonical, since this also means |
31 |
| -/// that T is canonical. |
32 |
| -Optional<Symbol> Rule::isPropertyRule() const { |
33 |
| - auto property = LHS.back(); |
34 |
| - |
35 |
| - if (!property.isProperty()) |
36 |
| - return None; |
37 |
| - |
38 |
| - if (LHS.size() - 1 != RHS.size()) |
39 |
| - return None; |
40 |
| - |
41 |
| - if (!std::equal(RHS.begin(), RHS.end(), LHS.begin())) |
42 |
| - return None; |
43 |
| - |
44 |
| - return property; |
45 |
| -} |
46 |
| - |
47 |
| -/// If this is a rule of the form T.[P] => T where [P] is a protocol symbol, |
48 |
| -/// return the protocol P, otherwise return nullptr. |
49 |
| -const ProtocolDecl *Rule::isProtocolConformanceRule() const { |
50 |
| - if (auto property = isPropertyRule()) { |
51 |
| - if (property->getKind() == Symbol::Kind::Protocol) |
52 |
| - return property->getProtocol(); |
53 |
| - } |
54 |
| - |
55 |
| - return nullptr; |
56 |
| -} |
57 |
| - |
58 |
| -/// If this is a rule of the form T.[concrete: C : P] => T where |
59 |
| -/// [concrete: C : P] is a concrete conformance symbol, return the protocol P, |
60 |
| -/// otherwise return nullptr. |
61 |
| -const ProtocolDecl *Rule::isAnyConformanceRule() const { |
62 |
| - if (auto property = isPropertyRule()) { |
63 |
| - switch (property->getKind()) { |
64 |
| - case Symbol::Kind::ConcreteConformance: |
65 |
| - case Symbol::Kind::Protocol: |
66 |
| - return property->getProtocol(); |
67 |
| - |
68 |
| - case Symbol::Kind::Layout: |
69 |
| - case Symbol::Kind::Superclass: |
70 |
| - case Symbol::Kind::ConcreteType: |
71 |
| - return nullptr; |
72 |
| - |
73 |
| - case Symbol::Kind::Name: |
74 |
| - case Symbol::Kind::AssociatedType: |
75 |
| - case Symbol::Kind::GenericParam: |
76 |
| - break; |
77 |
| - } |
78 |
| - |
79 |
| - llvm_unreachable("Bad symbol kind"); |
80 |
| - } |
81 |
| - |
82 |
| - return nullptr; |
83 |
| -} |
84 |
| - |
85 |
| -/// If this is a rule of the form [P].[P] => [P] where [P] is a protocol |
86 |
| -/// symbol, return true, otherwise return false. |
87 |
| -bool Rule::isIdentityConformanceRule() const { |
88 |
| - return (LHS.size() == 2 && |
89 |
| - RHS.size() == 1 && |
90 |
| - LHS[0] == RHS[0] && |
91 |
| - LHS[0] == LHS[1] && |
92 |
| - LHS[0].getKind() == Symbol::Kind::Protocol); |
93 |
| -} |
94 |
| - |
95 |
| -/// If this is a rule of the form [P].[Q] => [P] where [P] and [Q] are |
96 |
| -/// protocol symbols, return true, otherwise return false. |
97 |
| -bool Rule::isProtocolRefinementRule() const { |
98 |
| - if (LHS.size() == 2 && |
99 |
| - RHS.size() == 1 && |
100 |
| - LHS[0] == RHS[0] && |
101 |
| - LHS[0].getKind() == Symbol::Kind::Protocol && |
102 |
| - (LHS[1].getKind() == Symbol::Kind::Protocol || |
103 |
| - LHS[1].getKind() == Symbol::Kind::ConcreteConformance) && |
104 |
| - LHS[0] != LHS[1]) { |
105 |
| - |
106 |
| - // A protocol refinement rule must be from a directly-stated |
107 |
| - // inheritance clause entry. It can only become redundant if it is |
108 |
| - // written in terms of other protocol refinement rules; otherwise, it |
109 |
| - // must appear in the protocol's requirement signature. |
110 |
| - // |
111 |
| - // See RewriteSystem::isValidRefinementPath() for an explanation. |
112 |
| - auto *proto = LHS[0].getProtocol(); |
113 |
| - auto *otherProto = LHS[1].getProtocol(); |
114 |
| - |
115 |
| - auto inherited = proto->getInheritedProtocols(); |
116 |
| - return (std::find(inherited.begin(), inherited.end(), otherProto) |
117 |
| - != inherited.end()); |
118 |
| - } |
119 |
| - |
120 |
| - return false; |
121 |
| -} |
122 |
| - |
123 |
| -/// If this is a rule of the form [P].[concrete: C : Q] => [P] where |
124 |
| -/// [P] is a protocol symbol, return true. |
125 |
| -/// |
126 |
| -/// This means that P constrains 'Self' to a concrete type that conforms |
127 |
| -/// to some Q with P : Q. We don't consider this to be a valid conformance |
128 |
| -/// path element, to ensure compatibility with the GSB in an odd edge |
129 |
| -/// case: |
130 |
| -/// |
131 |
| -/// protocol P : C {} |
132 |
| -/// class C : P {} |
133 |
| -/// |
134 |
| -/// The GSB minimizes the signature <T where T : P> to <T where T : P>, |
135 |
| -/// whereas the minimal conformances algorithm would otherwise minimize |
136 |
| -/// it down to <T where T : C> on account of the (T.[P] => T) conformance |
137 |
| -/// rule being redundantly expressed via [P].[concrete: C : P]. |
138 |
| -bool Rule::isCircularConformanceRule() const { |
139 |
| - if (LHS.size() != 2 || RHS.size() != 1 || LHS[0] != RHS[0]) |
140 |
| - return false; |
141 |
| - |
142 |
| - if (LHS[0].getKind() != Symbol::Kind::Protocol || |
143 |
| - LHS[1].getKind() != Symbol::Kind::ConcreteConformance) |
144 |
| - return false; |
145 |
| - |
146 |
| - return true; |
147 |
| -} |
148 |
| - |
149 |
| -/// A protocol typealias rule takes one of the following two forms, |
150 |
| -/// where T is a name symbol: |
151 |
| -/// |
152 |
| -/// 1) [P].T => X |
153 |
| -/// 2) [P].T.[concrete: C] => [P].T |
154 |
| -/// |
155 |
| -/// The first case is where the protocol's underlying type is another |
156 |
| -/// type parameter. The second case is where the protocol's underlying |
157 |
| -/// type is a concrete type. |
158 |
| -/// |
159 |
| -/// In the first case, X must be fully resolved, that is, it must not |
160 |
| -/// contain any name symbols. |
161 |
| -/// |
162 |
| -/// If this rule is a protocol typealias rule, returns its name. Otherwise |
163 |
| -/// returns None. |
164 |
| -Optional<Identifier> Rule::isProtocolTypeAliasRule() const { |
165 |
| - if (LHS.size() != 2 && LHS.size() != 3) |
166 |
| - return None; |
167 |
| - |
168 |
| - if (LHS[0].getKind() != Symbol::Kind::Protocol || |
169 |
| - LHS[1].getKind() != Symbol::Kind::Name) |
170 |
| - return None; |
171 |
| - |
172 |
| - if (LHS.size() == 2) { |
173 |
| - // This is the case where the underlying type is a type parameter. |
174 |
| - // |
175 |
| - // We shouldn't have unresolved symbols on the right hand side; |
176 |
| - // they should have been simplified away. |
177 |
| - if (RHS.containsUnresolvedSymbols()) { |
178 |
| - if (RHS.size() != 2 || |
179 |
| - RHS[0] != LHS[0] || |
180 |
| - RHS[1].getKind() != Symbol::Kind::Name) { |
181 |
| - return None; |
182 |
| - } |
183 |
| - } |
184 |
| - } else { |
185 |
| - // This is the case where the underlying type is concrete. |
186 |
| - assert(LHS.size() == 3); |
187 |
| - |
188 |
| - auto prop = isPropertyRule(); |
189 |
| - if (!prop || prop->getKind() != Symbol::Kind::ConcreteType) |
190 |
| - return None; |
191 |
| - } |
192 |
| - |
193 |
| - return LHS[1].getName(); |
194 |
| -} |
195 |
| - |
196 |
| -/// A rule was derived from a concrete protocol typealias if it |
197 |
| -/// takes the following form: |
198 |
| -/// |
199 |
| -/// T.A.[concrete: C] => T.A |
200 |
| -/// |
201 |
| -/// Where the prefix term T does not contain any name symbols, and |
202 |
| -/// A is a name symbol. |
203 |
| -bool Rule::isDerivedFromConcreteProtocolTypeAliasRule() const { |
204 |
| - auto optSymbol = isPropertyRule(); |
205 |
| - if (!optSymbol || optSymbol->getKind() != Symbol::Kind::ConcreteType) |
206 |
| - return false; |
207 |
| - |
208 |
| - for (unsigned i = 0, e = RHS.size() - 1; i < e; ++i) { |
209 |
| - if (RHS[i].getKind() == Symbol::Kind::Name) |
210 |
| - return false; |
211 |
| - } |
212 |
| - |
213 |
| - if (RHS.back().getKind() != Symbol::Kind::Name) |
214 |
| - return false; |
215 |
| - |
216 |
| - return true; |
217 |
| -} |
218 |
| - |
219 |
| -/// Returns the length of the left hand side. |
220 |
| -unsigned Rule::getDepth() const { |
221 |
| - auto result = LHS.size(); |
222 |
| - |
223 |
| - if (LHS.back().hasSubstitutions()) { |
224 |
| - for (auto substitution : LHS.back().getSubstitutions()) { |
225 |
| - result = std::max(result, substitution.size()); |
226 |
| - } |
227 |
| - } |
228 |
| - |
229 |
| - return result; |
230 |
| -} |
231 |
| - |
232 |
| -/// Returns the nesting depth of the concrete symbol at the end of the |
233 |
| -/// left hand side, or 0 if there isn't one. |
234 |
| -unsigned Rule::getNesting() const { |
235 |
| - if (LHS.back().hasSubstitutions()) { |
236 |
| - auto type = LHS.back().getConcreteType(); |
237 |
| - |
238 |
| - struct Walker : TypeWalker { |
239 |
| - unsigned Nesting = 0; |
240 |
| - unsigned MaxNesting = 0; |
241 |
| - |
242 |
| - Action walkToTypePre(Type ty) override { |
243 |
| - ++Nesting; |
244 |
| - MaxNesting = std::max(Nesting, MaxNesting); |
245 |
| - |
246 |
| - return Action::Continue; |
247 |
| - } |
248 |
| - |
249 |
| - Action walkToTypePost(Type ty) override { |
250 |
| - --Nesting; |
251 |
| - |
252 |
| - return Action::Continue; |
253 |
| - } |
254 |
| - }; |
255 |
| - |
256 |
| - Walker walker; |
257 |
| - type.walk(walker); |
258 |
| - |
259 |
| - return walker.MaxNesting; |
260 |
| - } |
261 |
| - |
262 |
| - return 0; |
263 |
| -} |
264 |
| - |
265 |
| -/// Linear order on rules; compares LHS followed by RHS. |
266 |
| -Optional<int> Rule::compare(const Rule &other, RewriteContext &ctx) const { |
267 |
| - Optional<int> compare = LHS.compare(other.LHS, ctx); |
268 |
| - if (!compare.hasValue() || *compare != 0) |
269 |
| - return compare; |
270 |
| - |
271 |
| - return RHS.compare(other.RHS, ctx); |
272 |
| -} |
273 |
| - |
274 |
| -void Rule::dump(llvm::raw_ostream &out) const { |
275 |
| - out << LHS << " => " << RHS; |
276 |
| - if (Permanent) |
277 |
| - out << " [permanent]"; |
278 |
| - if (Explicit) |
279 |
| - out << " [explicit]"; |
280 |
| - if (LHSSimplified) |
281 |
| - out << " [lhs↓]"; |
282 |
| - if (RHSSimplified) |
283 |
| - out << " [rhs↓]"; |
284 |
| - if (SubstitutionSimplified) |
285 |
| - out << " [subst↓]"; |
286 |
| - if (Redundant) |
287 |
| - out << " [redundant]"; |
288 |
| - if (Conflicting) |
289 |
| - out << " [conflicting]"; |
290 |
| -} |
291 |
| - |
292 | 27 | RewriteSystem::RewriteSystem(RewriteContext &ctx)
|
293 | 28 | : Context(ctx), Debug(ctx.getDebugOptions()) {
|
294 | 29 | Initialized = 0;
|
|
0 commit comments