Skip to content

Commit acb12fa

Browse files
committed
RequirementMachine: More complete implementation of findProtocolConformanceRules()
1 parent c327074 commit acb12fa

File tree

2 files changed

+96
-125
lines changed

2 files changed

+96
-125
lines changed

lib/AST/RequirementMachine/GeneratingConformances.cpp

Lines changed: 92 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
//
3737
//===----------------------------------------------------------------------===//
3838

39+
#include "swift/AST/Decl.h"
3940
#include "swift/Basic/Defer.h"
4041
#include "swift/Basic/Range.h"
4142
#include "llvm/ADT/DenseMap.h"
@@ -52,49 +53,12 @@ using namespace rewriting;
5253
/// context, and with a non-empty left context. Applications of rules with a
5354
/// non-empty right context are ignored.
5455
void HomotopyGenerator::findProtocolConformanceRules(
55-
SmallVectorImpl<unsigned> &notInContext,
56-
SmallVectorImpl<std::pair<MutableTerm, unsigned>> &inContext,
56+
llvm::SmallDenseMap<const ProtocolDecl *,
57+
std::pair<SmallVector<unsigned, 2>,
58+
SmallVector<std::pair<MutableTerm, unsigned>, 2>>>
59+
&result,
5760
const RewriteSystem &system) const {
5861

59-
auto redundancyCandidates = Path.findRulesAppearingOnceInEmptyContext();
60-
if (redundancyCandidates.empty())
61-
return;
62-
63-
for (const auto &step : Path) {
64-
switch (step.Kind) {
65-
case RewriteStep::ApplyRewriteRule: {
66-
const auto &rule = system.getRule(step.RuleID);
67-
if (!rule.isProtocolConformanceRule())
68-
break;
69-
70-
if (!step.isInContext() &&
71-
step.Inverse &&
72-
std::find(redundancyCandidates.begin(),
73-
redundancyCandidates.end(),
74-
step.RuleID) != redundancyCandidates.end()) {
75-
notInContext.push_back(step.RuleID);
76-
}
77-
78-
break;
79-
}
80-
81-
case RewriteStep::AdjustConcreteType:
82-
break;
83-
}
84-
}
85-
86-
if (notInContext.empty())
87-
return;
88-
89-
if (notInContext.size() > 1) {
90-
llvm::errs() << "Multiple conformance rules appear once without context:\n";
91-
for (unsigned ruleID : notInContext)
92-
llvm::errs() << system.getRule(ruleID) << "\n";
93-
dump(llvm::errs(), system);
94-
llvm::errs() << "\n";
95-
abort();
96-
}
97-
9862
MutableTerm term = Basepoint;
9963

10064
for (const auto &step : Path) {
@@ -104,12 +68,16 @@ void HomotopyGenerator::findProtocolConformanceRules(
10468
if (!rule.isProtocolConformanceRule())
10569
break;
10670

107-
if (step.StartOffset > 0 &&
108-
step.EndOffset == 0 &&
109-
rule.getLHS().back() == system.getRule(notInContext[0]).getLHS().back()) {
71+
auto *proto = rule.getLHS().back().getProtocol();
72+
73+
if (!step.isInContext()) {
74+
result[proto].first.push_back(step.RuleID);
75+
} else if (step.StartOffset > 0 &&
76+
step.EndOffset == 0) {
11077
MutableTerm prefix(term.begin(), term.begin() + step.StartOffset);
111-
inContext.emplace_back(prefix, step.RuleID);
78+
result[proto].second.emplace_back(prefix, step.RuleID);
11279
}
80+
11381
break;
11482
}
11583

@@ -119,18 +87,6 @@ void HomotopyGenerator::findProtocolConformanceRules(
11987

12088
step.apply(term, system);
12189
}
122-
123-
if (inContext.empty()) {
124-
notInContext.clear();
125-
return;
126-
}
127-
128-
if (inContext.size() > 1) {
129-
llvm::errs() << "Multiple candidate conformance rules in context?\n";
130-
dump(llvm::errs(), system);
131-
llvm::errs() << "\n";
132-
abort();
133-
}
13490
}
13591

13692
/// Write the term as a product of left hand sides of protocol conformance
@@ -261,89 +217,102 @@ void RewriteSystem::computeCandidateConformancePaths(
261217
if (loop.isDeleted())
262218
continue;
263219

264-
SmallVector<unsigned, 2> notInContext;
265-
SmallVector<std::pair<MutableTerm, unsigned>, 2> inContext;
220+
llvm::SmallDenseMap<const ProtocolDecl *,
221+
std::pair<SmallVector<unsigned, 2>,
222+
SmallVector<std::pair<MutableTerm, unsigned>, 2>>>
223+
result;
266224

267-
loop.findProtocolConformanceRules(notInContext, inContext, *this);
225+
loop.findProtocolConformanceRules(result, *this);
268226

269-
if (notInContext.empty())
227+
if (result.empty())
270228
continue;
271229

272-
// We must either have multiple conformance rules in empty context, or
273-
// at least one conformance rule in non-empty context. Otherwise, we have
274-
// a conformance rule which is written as a series of same-type rules,
275-
// which doesn't make sense.
276-
assert(inContext.size() > 0 || notInContext.size() > 1);
277-
278230
if (Debug.contains(DebugFlags::GeneratingConformances)) {
279231
llvm::dbgs() << "Candidate homotopy generator: ";
280232
loop.dump(llvm::dbgs(), *this);
281233
llvm::dbgs() << "\n";
234+
}
282235

283-
llvm::dbgs() << "* Conformance rules not in context:\n";
284-
for (unsigned ruleID : notInContext) {
285-
llvm::dbgs() << "- (#" << ruleID << ") " << getRule(ruleID) << "\n";
286-
}
236+
for (const auto &pair : result) {
237+
const auto *proto = pair.first;
238+
const auto &notInContext = pair.second.first;
239+
const auto &inContext = pair.second.second;
287240

288-
llvm::dbgs() << "* Conformance rules in context:\n";
289-
for (auto pair : inContext) {
290-
llvm::dbgs() << "- " << pair.first;
291-
unsigned ruleID = pair.second;
292-
llvm::dbgs() << " (#" << ruleID << ") " << getRule(ruleID) << "\n";
241+
// No rules appear without context.
242+
if (notInContext.empty())
243+
continue;
244+
245+
// No replacement rules.
246+
if (notInContext.size() == 1 && inContext.empty())
247+
continue;
248+
249+
if (Debug.contains(DebugFlags::GeneratingConformances)) {
250+
llvm::dbgs() << "* Protocol " << proto->getName() << ":\n";
251+
llvm::dbgs() << "** Conformance rules not in context:\n";
252+
for (unsigned ruleID : notInContext) {
253+
llvm::dbgs() << "-- (#" << ruleID << ") " << getRule(ruleID) << "\n";
254+
}
255+
256+
llvm::dbgs() << "** Conformance rules in context:\n";
257+
for (auto pair : inContext) {
258+
llvm::dbgs() << "-- " << pair.first;
259+
unsigned ruleID = pair.second;
260+
llvm::dbgs() << " (#" << ruleID << ") " << getRule(ruleID) << "\n";
261+
}
262+
263+
llvm::dbgs() << "\n";
293264
}
294265

295-
llvm::dbgs() << "\n";
296-
}
266+
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
267+
// context, and a conformance rule (V.[P] => V) with a possibly non-empty
268+
// left context U and empty right context.
269+
//
270+
// We can decompose U into a product of conformance rules:
271+
//
272+
// (V1.[P1] => V1)...(Vn.[Pn] => Vn),
273+
//
274+
// Now, we can record a candidate decomposition of (T.[P] => T) as a
275+
// product of conformance rules:
276+
//
277+
// (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
278+
//
279+
// Now if U is empty, this becomes the trivial candidate:
280+
//
281+
// (T.[P] => T) := (V.[P] => V)
282+
SmallVector<SmallVector<unsigned, 2>, 2> candidatePaths;
283+
for (auto pair : inContext) {
284+
// We have a term U, and a rule V.[P] => V.
285+
SmallVector<unsigned, 2> conformancePath;
297286

298-
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
299-
// context, and a conformance rule (V.[P] => V) with a possibly non-empty
300-
// left context U and empty right context.
301-
//
302-
// We can decompose U into a product of conformance rules:
303-
//
304-
// (V1.[P1] => V1)...(Vn.[Pn] => Vn),
305-
//
306-
// Now, we can record a candidate decomposition of (T.[P] => T) as a
307-
// product of conformance rules:
308-
//
309-
// (T.[P] => T) := (V1.[P1] => V1)...(Vn.[Pn] => Vn).(V.[P] => V)
310-
//
311-
// Now if U is empty, this becomes the trivial candidate:
312-
//
313-
// (T.[P] => T) := (V.[P] => V)
314-
SmallVector<SmallVector<unsigned, 2>, 2> candidatePaths;
315-
for (auto pair : inContext) {
316-
// We have a term U, and a rule V.[P] => V.
317-
SmallVector<unsigned, 2> conformancePath;
318-
319-
// Simplify U to get U'.
320-
MutableTerm term = pair.first;
321-
(void) simplify(term);
322-
323-
// Write U'.[domain(V)] as a product of left hand sides of protocol
324-
// conformance rules.
325-
decomposeTermIntoConformanceRuleLeftHandSides(term, pair.second,
326-
conformancePath);
327-
328-
candidatePaths.push_back(conformancePath);
329-
}
287+
// Simplify U to get U'.
288+
MutableTerm term = pair.first;
289+
(void) simplify(term);
330290

331-
for (unsigned candidateRuleID : notInContext) {
332-
// If multiple conformance rules appear in an empty context, each one
333-
// can be replaced with any other conformance rule.
334-
for (unsigned otherRuleID : notInContext) {
335-
if (otherRuleID == candidateRuleID)
336-
continue;
291+
// Write U'.[domain(V)] as a product of left hand sides of protocol
292+
// conformance rules.
293+
decomposeTermIntoConformanceRuleLeftHandSides(term, pair.second,
294+
conformancePath);
337295

338-
SmallVector<unsigned, 2> path;
339-
path.push_back(otherRuleID);
340-
conformancePaths[candidateRuleID].push_back(path);
296+
candidatePaths.push_back(conformancePath);
341297
}
342298

343-
// If conformance rules appear in non-empty context, they define a
344-
// conformance access path for each conformance rule in empty context.
345-
for (const auto &path : candidatePaths) {
346-
conformancePaths[candidateRuleID].push_back(path);
299+
for (unsigned candidateRuleID : notInContext) {
300+
// If multiple conformance rules appear in an empty context, each one
301+
// can be replaced with any other conformance rule.
302+
for (unsigned otherRuleID : notInContext) {
303+
if (otherRuleID == candidateRuleID)
304+
continue;
305+
306+
SmallVector<unsigned, 2> path;
307+
path.push_back(otherRuleID);
308+
conformancePaths[candidateRuleID].push_back(path);
309+
}
310+
311+
// If conformance rules appear in non-empty context, they define a
312+
// conformance access path for each conformance rule in empty context.
313+
for (const auto &path : candidatePaths) {
314+
conformancePaths[candidateRuleID].push_back(path);
315+
}
347316
}
348317
}
349318
}

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,10 @@ class HomotopyGenerator {
300300
bool isInContext() const;
301301

302302
void findProtocolConformanceRules(
303-
SmallVectorImpl<unsigned> &notInContext,
304-
SmallVectorImpl<std::pair<MutableTerm, unsigned>> &inContext,
303+
llvm::SmallDenseMap<const ProtocolDecl *,
304+
std::pair<SmallVector<unsigned, 2>,
305+
SmallVector<std::pair<MutableTerm, unsigned>, 2>>>
306+
&result,
305307
const RewriteSystem &system) const;
306308

307309
void dump(llvm::raw_ostream &out, const RewriteSystem &system) const;

0 commit comments

Comments
 (0)