Skip to content

Commit f06f59a

Browse files
committed
RequirementMachine: Generalize relations so they look more like rules
1 parent 220d488 commit f06f59a

12 files changed

+114
-82
lines changed

lib/AST/RequirementMachine/PropertyRelations.cpp

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@
1818
using namespace swift;
1919
using namespace rewriting;
2020

21-
unsigned RewriteSystem::recordRelation(Symbol lhs, Symbol rhs) {
21+
RewriteSystem::Relation
22+
RewriteSystem::getRelation(unsigned index) const {
23+
return Relations[index];
24+
}
25+
26+
/// Record a relation that transforms the left hand side when it appears
27+
/// at the end of a term to the right hand side. Returns the relation ID,
28+
/// which can be passed to RewriteStep::forRelation().
29+
unsigned RewriteSystem::recordRelation(Term lhs, Term rhs) {
2230
auto key = std::make_pair(lhs, rhs);
2331
auto found = RelationMap.find(key);
2432
if (found != RelationMap.end())
@@ -33,9 +41,28 @@ unsigned RewriteSystem::recordRelation(Symbol lhs, Symbol rhs) {
3341
return index;
3442
}
3543

36-
RewriteSystem::Relation
37-
RewriteSystem::getRelation(unsigned index) const {
38-
return Relations[index];
44+
/// Given a left-hand side symbol [p1] and a right-hand side symbol
45+
/// [p2], record a relation ([p1].[p2] => [p1]), which denotes that
46+
/// the property p1 implies the property p2.
47+
///
48+
/// An example is a superclass requirement that implies a layout
49+
/// requirement.
50+
unsigned RewriteSystem::recordRelation(Symbol lhsProperty,
51+
Symbol rhsProperty) {
52+
assert(lhsProperty.isProperty());
53+
assert(rhsProperty.isProperty());
54+
55+
MutableTerm lhsTerm;
56+
lhsTerm.add(lhsProperty);
57+
lhsTerm.add(rhsProperty);
58+
59+
MutableTerm rhsTerm;
60+
rhsTerm.add(lhsProperty);
61+
62+
// Record a relation ([p1].[p2] => [p1]).
63+
return recordRelation(
64+
Term::get(lhsTerm, Context),
65+
Term::get(rhsTerm, Context));
3966
}
4067

4168
RewriteSystem::TypeWitness::TypeWitness(

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,30 +77,31 @@ static void recordRelation(Term key,
7777

7878
unsigned relationID = system.recordRelation(lhsProperty, rhsProperty);
7979

80-
/// Build the following rewrite path:
81-
///
82-
/// U.(V => V.[p1]).[p2] ⊗ U.V.Relation([p1].[p2] => [p1]) ⊗ U.(V.[p1] => V).
83-
///
80+
// Build the following rewrite path:
81+
//
82+
// U.(V => V.[p1]).[p2] ⊗ U.V.Relation([p1].[p2] => [p1]) ⊗ U.(V.[p1] => V).
83+
//
8484
RewritePath path;
8585

86-
/// Starting from U.V.[p2], apply the rule in reverse to get U.V.[p1].[p2].
86+
// Starting from U.V.[p2], apply the rule in reverse to get U.V.[p1].[p2].
8787
path.add(RewriteStep::forRewriteRule(
8888
/*startOffset=*/key.size() - lhsRule.getRHS().size(),
8989
/*endOffset=*/1,
9090
/*ruleID=*/lhsRuleID,
9191
/*inverse=*/true));
9292

93-
/// U.V.Relation([p1].[p2] => [p1]).
94-
path.add(RewriteStep::forRelation(relationID, /*inverse=*/false));
93+
// U.V.Relation([p1].[p2] => [p1]).
94+
path.add(RewriteStep::forRelation(/*startOffset=*/key.size(),
95+
relationID, /*inverse=*/false));
9596

96-
/// U.(V.[p1] => V).
97+
// U.(V.[p1] => V).
9798
path.add(RewriteStep::forRewriteRule(
9899
/*startOffset=*/key.size() - lhsRule.getRHS().size(),
99100
/*endOffset=*/0,
100101
/*ruleID=*/lhsRuleID,
101102
/*inverse=*/false));
102103

103-
/// Add the rule (T.[p2] => T) with the above rewrite path.
104+
// Add the rule (T.[p2] => T) with the above rewrite path.
104105
MutableTerm lhs(key);
105106
lhs.add(rhsProperty);
106107

lib/AST/RequirementMachine/RewriteLoop.cpp

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -65,16 +65,18 @@ void RewriteStep::dump(llvm::raw_ostream &out,
6565
break;
6666
}
6767
case Relation: {
68-
evaluator.applyRelation(*this, system);
68+
auto result = evaluator.applyRelation(*this, system);
6969

70-
auto relation = system.getRelation(Arg);
71-
out << "Relation(";
72-
if (Inverse) {
73-
out << relation.second << " > " << relation.first;
74-
} else {
75-
out << relation.first << " < " << relation.second;
70+
if (!result.prefix.empty()) {
71+
out << result.prefix;
72+
out << ".";
73+
}
74+
out << "(" << result.lhs << " =>> " << result.rhs << ")";
75+
if (!result.suffix.empty()) {
76+
out << ".";
77+
out << result.suffix;
7678
}
77-
out << ")";
79+
7880
break;
7981
}
8082
case ConcreteConformance: {
@@ -293,41 +295,6 @@ void RewritePathEvaluator::applyShift(const RewriteStep &step,
293295
}
294296
}
295297

296-
void RewritePathEvaluator::applyRelation(const RewriteStep &step,
297-
const RewriteSystem &system) {
298-
assert(step.Kind == RewriteStep::Relation);
299-
300-
auto relation = system.getRelation(step.Arg);
301-
auto &term = getCurrentTerm();
302-
303-
if (!step.Inverse) {
304-
// Given a term T.[p1].[p2].U where |U| == EndOffset, build the
305-
// term T.[p1].U.
306-
307-
auto lhsProperty = *(term.end() - step.EndOffset - 2);
308-
auto rhsProperty = *(term.end() - step.EndOffset - 1);
309-
assert(lhsProperty == relation.first);
310-
assert(rhsProperty == relation.second);
311-
312-
MutableTerm result(term.begin(), term.end() - step.EndOffset - 1);
313-
result.append(term.end() - step.EndOffset, term.end());
314-
315-
term = result;
316-
} else {
317-
// Given a term T.[p1].U where |U| == EndOffset, build the
318-
// term T.[p1].[p2].U.
319-
320-
auto lhsProperty = *(term.end() - step.EndOffset - 1);
321-
assert(lhsProperty == relation.first);
322-
323-
MutableTerm result(term.begin(), term.end() - step.EndOffset);
324-
result.add(relation.second);
325-
result.append(term.end() - step.EndOffset, term.end());
326-
327-
term = result;
328-
}
329-
}
330-
331298
void RewritePathEvaluator::applyDecompose(const RewriteStep &step,
332299
const RewriteSystem &system) {
333300
assert(step.Kind == RewriteStep::Decompose);
@@ -404,6 +371,46 @@ void RewritePathEvaluator::applyDecompose(const RewriteStep &step,
404371
}
405372
}
406373

374+
AppliedRewriteStep
375+
RewritePathEvaluator::applyRelation(const RewriteStep &step,
376+
const RewriteSystem &system) {
377+
assert(step.Kind == RewriteStep::Relation);
378+
379+
auto relation = system.getRelation(step.Arg);
380+
auto &term = getCurrentTerm();
381+
382+
auto lhs = (step.Inverse ? relation.second : relation.first);
383+
auto rhs = (step.Inverse ? relation.first : relation.second);
384+
385+
auto bug = [&](StringRef msg) {
386+
llvm::errs() << msg << "\n";
387+
llvm::errs() << "- Term: " << term << "\n";
388+
llvm::errs() << "- StartOffset: " << step.StartOffset << "\n";
389+
llvm::errs() << "- EndOffset: " << step.EndOffset << "\n";
390+
llvm::errs() << "- Expected subterm: " << lhs << "\n";
391+
abort();
392+
};
393+
394+
if (term.size() != step.StartOffset + lhs.size() + step.EndOffset) {
395+
bug("Invalid whiskering");
396+
}
397+
398+
if (!std::equal(term.begin() + step.StartOffset,
399+
term.begin() + step.StartOffset + lhs.size(),
400+
lhs.begin())) {
401+
bug("Invalid subterm");
402+
}
403+
404+
MutableTerm prefix(term.begin(), term.begin() + step.StartOffset);
405+
MutableTerm suffix(term.end() - step.EndOffset, term.end());
406+
407+
term = prefix;
408+
term.append(rhs);
409+
term.append(suffix);
410+
411+
return {lhs, rhs, prefix, suffix};
412+
}
413+
407414
void
408415
RewritePathEvaluator::applyConcreteConformance(const RewriteStep &step,
409416
const RewriteSystem &system) {

lib/AST/RequirementMachine/RewriteLoop.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,9 @@ struct RewriteStep {
209209
/*arg=*/numSubstitutions, inverse);
210210
}
211211

212-
static RewriteStep forRelation(unsigned relationID, bool inverse) {
213-
return RewriteStep(Relation, /*startOffset=*/0, /*endOffset=*/0,
212+
static RewriteStep forRelation(unsigned startOffset, unsigned relationID,
213+
bool inverse) {
214+
return RewriteStep(Relation, startOffset, /*endOffset=*/0,
214215
/*arg=*/relationID, inverse);
215216
}
216217

@@ -420,12 +421,13 @@ struct RewritePathEvaluator {
420421
void applyShift(const RewriteStep &step,
421422
const RewriteSystem &system);
422423

423-
void applyRelation(const RewriteStep &step,
424-
const RewriteSystem &system);
425-
426424
void applyDecompose(const RewriteStep &step,
427425
const RewriteSystem &system);
428426

427+
AppliedRewriteStep
428+
applyRelation(const RewriteStep &step,
429+
const RewriteSystem &system);
430+
429431
void applyConcreteConformance(const RewriteStep &step,
430432
const RewriteSystem &system);
431433

lib/AST/RequirementMachine/RewriteSystem.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,11 @@ void RewriteSystem::dump(llvm::raw_ostream &out) const {
699699
out << "- " << rule << "\n";
700700
}
701701
out << "}\n";
702+
out << "Relations: {\n";
703+
for (const auto &relation : Relations) {
704+
out << "- " << relation.first << " =>> " << relation.second << "\n";
705+
}
706+
out << "}\n";
702707
out << "Rewrite loops: {\n";
703708
for (const auto &loop : Loops) {
704709
if (loop.isDeleted())

lib/AST/RequirementMachine/RewriteSystem.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,22 +329,24 @@ class RewriteSystem final {
329329

330330
//////////////////////////////////////////////////////////////////////////////
331331
///
332-
/// "Pseudo-rules" for the property map
332+
/// Relations are "pseudo-rules" introduced by the property map
333333
///
334334
//////////////////////////////////////////////////////////////////////////////
335335

336336
public:
337337
/// The left hand side is known to be smaller than the right hand side.
338-
using Relation = std::pair<Symbol, Symbol>;
338+
using Relation = std::pair<Term, Term>;
339339

340340
private:
341341
llvm::DenseMap<Relation, unsigned> RelationMap;
342342
std::vector<Relation> Relations;
343343

344344
public:
345-
unsigned recordRelation(Symbol lhs, Symbol rhs);
345+
unsigned recordRelation(Term lhs, Term rhs);
346346
Relation getRelation(unsigned index) const;
347347

348+
unsigned recordRelation(Symbol lhs, Symbol rhs);
349+
348350
/// A type witness has a subject type, stored in LHS, which takes the form:
349351
///
350352
/// T.[concrete: C : P].[P:X]

test/Generics/generic_objc_superclass.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ func foo<T : Generic<U>, U>(_: T, _: U) {
1616
// CHECK-NEXT: - τ_0_0.[superclass: Generic<τ_0_0> with <τ_0_1>] => τ_0_0
1717
// CHECK-NEXT: - τ_0_0.[layout: AnyObject] => τ_0_0
1818
// CHECK-NEXT: }
19-
// CHECK-NEXT: Rewrite loops: {
20-
// CHECK-NEXT: }
21-
// CHECK-NEXT: Property map: {
19+
// CHECK: Property map: {
2220
// CHECK-NEXT: τ_0_0 => { layout: AnyObject superclass: [superclass: Generic<τ_0_0> with <τ_0_1>] }
2321
// CHECK-NEXT: }

test/Generics/rdar79564324.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,7 @@ public func test<T : P>(_ t: T) where T == T.A {
3535
// CHECK-NEXT: - τ_0_1.A => τ_0_0
3636
// CHECK-NEXT: - τ_0_0.A => τ_0_0
3737
// CHECK-NEXT: }
38-
// CHECK-NEXT: Rewrite loops: {
39-
// CHECK: }
40-
// CHECK-NEXT: Property map: {
38+
// CHECK: Property map: {
4139
// CHECK-NEXT: [P] => { conforms_to: [P] }
4240
// CHECK-NEXT: [P:A] => { conforms_to: [P] }
4341
// CHECK-NEXT: τ_0_1 => { conforms_to: [P] }

test/Generics/unify_superclass_types_1.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@ extension P where Self : Derived {
2323
// CHECK-NEXT: - [P].[layout: _NativeClass] => [P]
2424
// CHECK-NEXT: - τ_0_0.[layout: _NativeClass] => τ_0_0
2525
// CHECK-NEXT: }
26-
// CHECK-NEXT: Rewrite loops: {
27-
// CHECK: }
28-
// CHECK-NEXT: Property map: {
26+
// CHECK: Property map: {
2927
// CHECK-NEXT: [P] => { conforms_to: [P] layout: _NativeClass superclass: [superclass: Base] }
3028
// CHECK-NEXT: τ_0_0 => { conforms_to: [P] layout: _NativeClass superclass: [superclass: Derived] }
3129
// CHECK-NEXT: }

test/Generics/unify_superclass_types_2.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@ func unifySuperclassTest<T : P1 & P2>(_: T) {
4141
// CHECK-NEXT: - τ_0_0.[P1:A1].[concrete: String] => τ_0_0.[P1:A1]
4242
// CHECK-NEXT: - τ_0_0.[P2:B2] => τ_0_0.[P1:B1]
4343
// CHECK: }
44-
// CHECK-NEXT: Rewrite loops: {
45-
// CHECK: }
46-
// CHECK-NEXT: Property map: {
44+
// CHECK: Property map: {
4745
// CHECK-NEXT: [P1] => { conforms_to: [P1] }
4846
// CHECK-NEXT: [P2] => { conforms_to: [P2] }
4947
// CHECK-NEXT: [P1:X] => { layout: _NativeClass superclass: [superclass: Generic<Int, τ_0_0, τ_0_1> with <[P1:A1], [P1:B1]>] }

0 commit comments

Comments
 (0)