Skip to content

Commit 755941c

Browse files
committed
RequirementMachine: Split off Rule.cpp from RewriteSystem.cpp
1 parent f807ef9 commit 755941c

File tree

6 files changed

+507
-448
lines changed

6 files changed

+507
-448
lines changed

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ add_swift_host_library(swiftAST STATIC
9494
RequirementMachine/RewriteContext.cpp
9595
RequirementMachine/RewriteLoop.cpp
9696
RequirementMachine/RewriteSystem.cpp
97+
RequirementMachine/Rule.cpp
9798
RequirementMachine/SimplifySubstitutions.cpp
9899
RequirementMachine/Symbol.cpp
99100
RequirementMachine/Term.cpp

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 3 additions & 268 deletions
Original file line numberDiff line numberDiff line change
@@ -12,283 +12,18 @@
1212

1313
#include "swift/AST/Decl.h"
1414
#include "swift/AST/Types.h"
15-
#include "swift/AST/TypeWalker.h"
16-
#include "llvm/ADT/FoldingSet.h"
1715
#include "llvm/Support/raw_ostream.h"
1816
#include <algorithm>
1917
#include <vector>
2018
#include "RewriteContext.h"
19+
#include "RewriteLoop.h"
2120
#include "RewriteSystem.h"
21+
#include "Rule.h"
22+
#include "Trie.h"
2223

2324
using namespace swift;
2425
using namespace rewriting;
2526

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-
29227
RewriteSystem::RewriteSystem(RewriteContext &ctx)
29328
: Context(ctx), Debug(ctx.getDebugOptions()) {
29429
Initialized = 0;

0 commit comments

Comments
 (0)