|
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