Skip to content

Commit c6403e6

Browse files
committed
RequirementMachine: RewriteStep stores both whiskers
1 parent 5cbfbae commit c6403e6

File tree

7 files changed

+134
-67
lines changed

7 files changed

+134
-67
lines changed

lib/AST/RequirementMachine/Debug.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ enum class DebugFlags : unsigned {
3535

3636
/// Print debug output when concretizing nested types in the property map.
3737
ConcretizeNestedTypes = (1<<5)
38+
39+
/// Print debug output from the homotopy reduction algorithm.
40+
HomotopyReduction = (1<<7),
3841
};
3942

4043
using DebugOptions = OptionSet<DebugFlags>;
@@ -43,4 +46,4 @@ using DebugOptions = OptionSet<DebugFlags>;
4346

4447
}
4548

46-
#endif
49+
#endif

lib/AST/RequirementMachine/RequirementMachine.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,3 +448,7 @@ void RequirementMachine::computeCompletion() {
448448
bool RequirementMachine::isComplete() const {
449449
return Complete;
450450
}
451+
452+
void RequirementMachine::computeMinimalRequirements(const ProtocolDecl *proto) {
453+
System.minimizeRewriteSystem();
454+
}

lib/AST/RequirementMachine/RequirementMachine.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class RequirementMachine final {
107107
ProtocolDecl *protocol);
108108
TypeDecl *lookupNestedType(Type depType, Identifier name) const;
109109

110+
void computeMinimalRequirements(const ProtocolDecl *proto);
111+
110112
void verify(const MutableTerm &term) const;
111113
void dump(llvm::raw_ostream &out) const;
112114
};

lib/AST/RequirementMachine/RewriteContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ static DebugOptions parseDebugFlags(StringRef debugFlags) {
3333
.Case("completion", DebugFlags::Completion)
3434
.Case("concrete-unification", DebugFlags::ConcreteUnification)
3535
.Case("concretize-nested-types", DebugFlags::ConcretizeNestedTypes)
36+
.Case("homotopy-reduction", DebugFlags::HomotopyReduction)
3637
.Default(None);
3738
if (!flag) {
3839
llvm::errs() << "Unknown debug flag in -debug-requirement-machine "

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -46,18 +46,27 @@ RewriteStep::applyRewriteRule(MutableTerm &term,
4646
auto lhs = (Inverse ? rule.getRHS() : rule.getLHS());
4747
auto rhs = (Inverse ? rule.getLHS() : rule.getRHS());
4848

49-
if (!std::equal(term.begin() + Offset,
50-
term.begin() + Offset + lhs.size(),
51-
lhs.begin())) {
52-
llvm::errs() << "Invalid rewrite path\n";
49+
auto bug = [&](StringRef msg) {
50+
llvm::errs() << msg << "\n";
5351
llvm::errs() << "- Term: " << term << "\n";
54-
llvm::errs() << "- Offset: " << Offset << "\n";
52+
llvm::errs() << "- StartOffset: " << StartOffset << "\n";
53+
llvm::errs() << "- EndOffset: " << EndOffset << "\n";
5554
llvm::errs() << "- Expected subterm: " << lhs << "\n";
5655
abort();
56+
};
57+
58+
if (term.size() != StartOffset + lhs.size() + EndOffset) {
59+
bug("Invalid whiskering");
60+
}
61+
62+
if (!std::equal(term.begin() + StartOffset,
63+
term.begin() + StartOffset + lhs.size(),
64+
lhs.begin())) {
65+
bug("Invalid subterm");
5766
}
5867

59-
MutableTerm prefix(term.begin(), term.begin() + Offset);
60-
MutableTerm suffix(term.begin() + Offset + lhs.size(), term.end());
68+
MutableTerm prefix(term.begin(), term.begin() + StartOffset);
69+
MutableTerm suffix(term.end() - EndOffset, term.end());
6170

6271
term = prefix;
6372
term.append(rhs);
@@ -69,25 +78,27 @@ RewriteStep::applyRewriteRule(MutableTerm &term,
6978
MutableTerm RewriteStep::applyAdjustment(MutableTerm &term,
7079
const RewriteSystem &system) const {
7180
assert(Kind == AdjustConcreteType);
81+
assert(EndOffset == 0);
82+
assert(RuleID == 0);
7283

7384
auto &ctx = system.getRewriteContext();
74-
MutableTerm prefix(term.begin(), term.begin() + Offset);
85+
MutableTerm prefix(term.begin(), term.begin() + StartOffset);
7586

7687
// We're either adding or removing the prefix to each concrete substitution.
7788
term.back() = term.back().transformConcreteSubstitutions(
7889
[&](Term t) -> Term {
7990
if (Inverse) {
8091
if (!std::equal(t.begin(),
81-
t.begin() + Offset,
92+
t.begin() + StartOffset,
8293
prefix.begin())) {
8394
llvm::errs() << "Invalid rewrite path\n";
8495
llvm::errs() << "- Term: " << term << "\n";
85-
llvm::errs() << "- Offset: " << Offset << "\n";
96+
llvm::errs() << "- Start offset: " << StartOffset << "\n";
8697
llvm::errs() << "- Expected subterm: " << prefix << "\n";
8798
abort();
8899
}
89100

90-
MutableTerm mutTerm(t.begin() + Offset, t.end());
101+
MutableTerm mutTerm(t.begin() + StartOffset, t.end());
91102
return Term::get(mutTerm, ctx);
92103
} else {
93104
MutableTerm mutTerm(prefix);
@@ -99,6 +110,18 @@ MutableTerm RewriteStep::applyAdjustment(MutableTerm &term,
99110
return prefix;
100111
}
101112

113+
void RewriteStep::apply(MutableTerm &term, const RewriteSystem &system) const {
114+
switch (Kind) {
115+
case ApplyRewriteRule:
116+
(void) applyRewriteRule(term, system);
117+
break;
118+
119+
case AdjustConcreteType:
120+
(void) applyAdjustment(term, system);
121+
break;
122+
}
123+
}
124+
102125
/// Dumps the rewrite step that was applied to \p term. Mutates \p term to
103126
/// reflect the application of the rule.
104127
void RewriteStep::dump(llvm::raw_ostream &out,
@@ -264,7 +287,8 @@ bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
264287
if (path) {
265288
// We have a rewrite path from the simplified lhs to the simplified rhs;
266289
// add a rewrite step applying the new rule in reverse to close the loop.
267-
loop.add(RewriteStep::forRewriteRule(/*offset=*/0, newRuleID, /*inverse=*/true));
290+
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
291+
newRuleID, /*inverse=*/true));
268292
HomotopyGenerators.emplace_back(lhs, loop);
269293

270294
if (Debug.contains(DebugFlags::Add)) {
@@ -322,11 +346,13 @@ bool RewriteSystem::simplify(MutableTerm &term, RewritePath *path) const {
322346
auto to = from + rule.getLHS().size();
323347
assert(std::equal(from, to, rule.getLHS().begin()));
324348

349+
unsigned startOffset = (unsigned)(from - term.begin());
350+
unsigned endOffset = term.size() - rule.getLHS().size() - startOffset;
351+
325352
term.rewriteSubTerm(from, to, rule.getRHS());
326353

327354
if (path) {
328-
unsigned offset = (unsigned)(from - term.begin());
329-
path->add(RewriteStep::forRewriteRule(offset, *ruleID,
355+
path->add(RewriteStep::forRewriteRule(startOffset, endOffset, *ruleID,
330356
/*inverse=*/false));
331357
}
332358

@@ -426,12 +452,12 @@ void RewriteSystem::simplifyRewriteSystem() {
426452

427453
// (2) Next, apply the original rule in reverse to produce the
428454
// original lhs.
429-
loop.add(RewriteStep::forRewriteRule(/*offset=*/0, ruleID,
430-
/*inverse=*/true));
455+
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
456+
ruleID, /*inverse=*/true));
431457

432458
// (3) Finally, apply the new rule to produce the simplified rhs.
433-
loop.add(RewriteStep::forRewriteRule(/*offset=*/0, newRuleID,
434-
/*inverse=*/false));
459+
loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
460+
newRuleID, /*inverse=*/false));
435461

436462
if (Debug.contains(DebugFlags::Completion)) {
437463
llvm::dbgs() << "$ Right hand side simplification recorded a loop: ";
@@ -510,14 +536,7 @@ void RewriteSystem::verifyHomotopyGenerators() const {
510536
auto term = loop.first;
511537

512538
for (const auto &step : loop.second) {
513-
switch (step.Kind) {
514-
case RewriteStep::ApplyRewriteRule:
515-
(void) step.applyRewriteRule(term, *this);
516-
break;
517-
case RewriteStep::AdjustConcreteType:
518-
(void) step.applyAdjustment(term, *this);
519-
break;
520-
}
539+
step.apply(term, *this);
521540
}
522541

523542
if (term != loop.first) {

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,13 @@ struct RewriteStep {
107107
/// The rewrite step kind.
108108
unsigned Kind : 1;
109109

110-
/// The position within the term where the rule is being applied.
111-
unsigned Offset : 15;
110+
/// The size of the left whisker, which is the position within the term where
111+
/// the rule is being applied. In A.(X => Y).B, this is |A|=1.
112+
unsigned StartOffset : 7;
113+
114+
/// The size of the right whisker, which is the length of the remaining suffix
115+
/// after the rule is applied. In A.(X => Y).B, this is |B|=1.
116+
unsigned EndOffset : 7;
112117

113118
/// The index of the rule in the rewrite system.
114119
unsigned RuleID : 15;
@@ -117,22 +122,27 @@ struct RewriteStep {
117122
/// with the right hand side. If true, vice versa.
118123
unsigned Inverse : 1;
119124

120-
RewriteStep(StepKind kind, unsigned offset, unsigned ruleID, bool inverse) {
125+
RewriteStep(StepKind kind, unsigned startOffset, unsigned endOffset,
126+
unsigned ruleID, bool inverse) {
121127
Kind = unsigned(kind);
122128

123-
Offset = offset;
124-
assert(Offset == offset && "Overflow");
129+
StartOffset = startOffset;
130+
assert(StartOffset == startOffset && "Overflow");
131+
EndOffset = endOffset;
132+
assert(EndOffset == endOffset && "Overflow");
125133
RuleID = ruleID;
126134
assert(RuleID == ruleID && "Overflow");
127135
Inverse = inverse;
128136
}
129137

130-
static RewriteStep forRewriteRule(unsigned offset, unsigned ruleID, bool inverse) {
131-
return RewriteStep(ApplyRewriteRule, offset, ruleID, inverse);
138+
static RewriteStep forRewriteRule(unsigned startOffset, unsigned endOffset,
139+
unsigned ruleID, bool inverse) {
140+
return RewriteStep(ApplyRewriteRule, startOffset, endOffset, ruleID, inverse);
132141
}
133142

134143
static RewriteStep forAdjustment(unsigned offset, bool inverse) {
135-
return RewriteStep(AdjustConcreteType, offset, /*ruleID=*/0, inverse);
144+
return RewriteStep(AdjustConcreteType, offset, /*endOffset=*/0,
145+
/*ruleID=*/0, inverse);
136146
}
137147

138148
void invert() {
@@ -145,6 +155,8 @@ struct RewriteStep {
145155
MutableTerm applyAdjustment(MutableTerm &term,
146156
const RewriteSystem &system) const;
147157

158+
void apply(MutableTerm &term, const RewriteSystem &system) const;
159+
148160
void dump(llvm::raw_ostream &out,
149161
MutableTerm &term,
150162
const RewriteSystem &system) const;
@@ -158,6 +170,10 @@ struct RewritePath {
158170
return Steps.empty();
159171
}
160172

173+
unsigned size() const {
174+
return Steps.size();
175+
}
176+
161177
void add(RewriteStep step) {
162178
Steps.push_back(step);
163179
}
@@ -223,9 +239,19 @@ class RewriteSystem final {
223239
/// Pairs of rules which have already been checked for overlap.
224240
llvm::DenseSet<std::pair<unsigned, unsigned>> CheckedOverlaps;
225241

226-
/// Homotopy generators (2-cells) for this rewrite system. These are the
227-
/// cyclic rewrite paths which rewrite a term back to itself. This
228-
/// data informs the generic signature minimization algorithm.
242+
/// Homotopy generators for this rewrite system. These are the
243+
/// cyclic rewrite paths which rewrite a term back to itself.
244+
///
245+
/// In the category theory interpretation, a rewrite rule is a generating
246+
/// 2-cell, and a rewrite path is a 2-cell made from a composition of
247+
/// generating 2-cells.
248+
///
249+
/// Homotopy generators, in turn, are 3-cells. The special case of a
250+
/// 3-cell discovered during completion can be viewed as two parallel
251+
/// 2-cells; this is actually represented as a single 2-cell forming a
252+
/// loop around a base point.
253+
///
254+
/// This data informs the generic signature minimization algorithm.
229255
std::vector<std::pair<MutableTerm, RewritePath>> HomotopyGenerators;
230256

231257
DebugOptions Debug;

lib/AST/RequirementMachine/RewriteSystemCompletion.cpp

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -380,22 +380,31 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
380380
//
381381
// In this case, T and V are both empty.
382382

383+
// Compute the terms T and V.
384+
MutableTerm t(lhs.getLHS().begin(), from);
385+
MutableTerm v(from + rhs.getLHS().size(), lhs.getLHS().end());
386+
383387
// Compute the term TYV.
384-
MutableTerm tyv(lhs.getLHS().begin(), from);
388+
MutableTerm tyv(t);
385389
tyv.append(rhs.getRHS());
386-
tyv.append(from + rhs.getLHS().size(), lhs.getLHS().end());
390+
tyv.append(v);
387391

388392
MutableTerm x(lhs.getRHS());
389393

390-
// Compute a path from X to TYV.
394+
// Compute a path from X to TYV: (X => TUV) ⊗ T.(U => Y).V
391395
RewritePath path;
392396

393-
// (1) First, apply the left hand side rule in the reverse direction.
394-
path.add(RewriteStep::forRewriteRule(/*offset=*/0,
397+
// (1) First, apply the left hand side rule in the reverse direction:
398+
//
399+
// (X => TUV)
400+
path.add(RewriteStep::forRewriteRule(/*startOffset=*/0,
401+
/*endOffset=*/0,
395402
getRuleID(lhs),
396403
/*inverse=*/true));
397-
// (2) Now, apply the right hand side in the forward direction.
398-
path.add(RewriteStep::forRewriteRule(from - lhs.getLHS().begin(),
404+
// (2) Now, apply the right hand side in the forward direction:
405+
//
406+
// T.(U => Y).V
407+
path.add(RewriteStep::forRewriteRule(t.size(), v.size(),
399408
getRuleID(rhs),
400409
/*inverse=*/false));
401410

@@ -411,52 +420,55 @@ RewriteSystem::computeCriticalPair(ArrayRef<Symbol>::const_iterator from,
411420
} else {
412421
// lhs == TU -> X, rhs == UV -> Y.
413422

414-
// Compute the term T.
423+
// Compute the terms T and V.
415424
MutableTerm t(lhs.getLHS().begin(), from);
425+
MutableTerm v(rhs.getLHS().begin() + (lhs.getLHS().end() - from),
426+
rhs.getLHS().end());
416427

417428
// Compute the term XV.
418429
MutableTerm xv(lhs.getRHS());
419-
xv.append(rhs.getLHS().begin() + (lhs.getLHS().end() - from),
420-
rhs.getLHS().end());
421-
422-
if (xv.back().isSuperclassOrConcreteType() &&
423-
lhs.getLHS().begin() != from) {
424-
xv.back() = xv.back().prependPrefixToConcreteSubstitutions(
425-
t, Context);
426-
}
430+
xv.append(v);
427431

428432
// Compute the term TY.
429-
t.append(rhs.getRHS());
433+
MutableTerm ty(t);
434+
ty.append(rhs.getRHS());
430435

431-
// Compute a path from XV to TY.
436+
// Compute a path from XV to TY: (X => TU).V ⊗ (σ - T) ⊗ T.(UV => Y)
432437
RewritePath path;
433438

434-
// (1) First, apply the left hand side rule in the reverse direction.
435-
path.add(RewriteStep::forRewriteRule(/*offset=*/0,
439+
// (1) First, apply the left hand side rule in the reverse direction:
440+
//
441+
// (X => TU).V
442+
path.add(RewriteStep::forRewriteRule(/*startOffset=*/0, v.size(),
436443
getRuleID(lhs),
437444
/*inverse=*/true));
438445

439446
// (2) Next, if the right hand side rule ends with a concrete type symbol,
440-
// perform the concrete type adjustment.
441-
if (xv.back().isSuperclassOrConcreteType() &&
442-
lhs.getLHS().begin() != from) {
443-
path.add(RewriteStep::forAdjustment(from - lhs.getLHS().begin(),
444-
/*inverse=*/true));
447+
// perform the concrete type adjustment:
448+
//
449+
// (σ - T)
450+
if (xv.back().isSuperclassOrConcreteType() && t.size() > 0) {
451+
path.add(RewriteStep::forAdjustment(t.size(), /*inverse=*/true));
452+
453+
xv.back() = xv.back().prependPrefixToConcreteSubstitutions(
454+
t, Context);
445455
}
446456

447-
// (3) Finally, apply the right hand side in the forward direction.
448-
path.add(RewriteStep::forRewriteRule(from - lhs.getLHS().begin(),
457+
// (3) Finally, apply the right hand side in the forward direction:
458+
//
459+
// T.(UV => Y)
460+
path.add(RewriteStep::forRewriteRule(t.size(), /*endOffset=*/0,
449461
getRuleID(rhs),
450462
/*inverse=*/false));
451463

452464
// If XV == TY, we have a trivial overlap.
453-
if (xv == t) {
465+
if (xv == ty) {
454466
loops.emplace_back(xv, path);
455467
return false;
456468
}
457469

458470
// Add the pair (XV, TY).
459-
pairs.emplace_back(xv, t);
471+
pairs.emplace_back(xv, ty);
460472
paths.push_back(path);
461473
}
462474

0 commit comments

Comments
 (0)