Skip to content

Commit 9e234a0

Browse files
committed
RequirementMachine: Record rewrite loop relating concrete type rules in processTypeDifference()
We can't actually rely on concretelySimplifyLeftHandSideSubstitutions() to do this for us, because the less-simplified rule (the LHS rule) might only apply to a suffix of the base term.
1 parent 5bb8028 commit 9e234a0

File tree

2 files changed

+59
-10
lines changed

2 files changed

+59
-10
lines changed

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -522,10 +522,8 @@ static void buildRewritePathForInducedRule(unsigned differenceID,
522522
/// concrete type rules, since the concrete type rules imply the induced
523523
/// rules and make them redundant.
524524
///
525-
/// The implication going in the other direction -- where one of the
526-
/// two concrete type rules together with the induced rules implies the
527-
/// other concrete type rule -- is recorded in
528-
/// concretelySimplifyLeftHandSideSubstitutions().
525+
/// Finally, builds a rewrite loop relating the two concrete type rules
526+
/// via the induced rules.
529527
void PropertyMap::processTypeDifference(const TypeDifference &difference,
530528
unsigned differenceID,
531529
unsigned lhsRuleID,
@@ -536,23 +534,75 @@ void PropertyMap::processTypeDifference(const TypeDifference &difference,
536534
difference.dump(llvm::dbgs());
537535
}
538536

539-
for (unsigned index : indices(difference.LHS.getSubstitutions())) {
537+
RewritePath unificationPath;
538+
539+
auto substitutions = difference.LHS.getSubstitutions();
540+
541+
// The term is at the top of the primary stack. Push all substitutions onto
542+
// the primary stack.
543+
unificationPath.add(RewriteStep::forDecompose(substitutions.size(),
544+
/*inverse=*/false));
545+
546+
// Move all substitutions but the first one to the secondary stack.
547+
for (unsigned i = 1; i < substitutions.size(); ++i)
548+
unificationPath.add(RewriteStep::forShift(/*inverse=*/false));
549+
550+
for (unsigned index : indices(substitutions)) {
551+
// Move the next substitution from the secondary stack to the primary stack.
552+
if (index != 0)
553+
unificationPath.add(RewriteStep::forShift(/*inverse=*/true));
554+
540555
auto lhsTerm = difference.getReplacementSubstitution(index);
541556
auto rhsTerm = difference.getOriginalSubstitution(index);
542557

543-
RewritePath path;
558+
RewritePath inducedRulePath;
544559
buildRewritePathForInducedRule(differenceID, lhsRuleID, rhsRuleID,
545-
index, System, path);
560+
index, System, inducedRulePath);
546561

547562
if (debug) {
548563
llvm::dbgs() << "%% Induced rule " << lhsTerm
549564
<< " => " << rhsTerm << " with path ";
550-
path.dump(llvm::dbgs(), lhsTerm, System);
565+
inducedRulePath.dump(llvm::dbgs(), lhsTerm, System);
551566
llvm::dbgs() << "\n";
552567
}
553568

554-
System.addRule(lhsTerm, rhsTerm, &path);
569+
System.addRule(lhsTerm, rhsTerm, &inducedRulePath);
570+
571+
// Build a path from rhsTerm (the original substitution) to
572+
// lhsTerm (the replacement substitution).
573+
MutableTerm mutRhsTerm(rhsTerm);
574+
(void) System.simplify(mutRhsTerm, &unificationPath);
575+
576+
RewritePath lhsPath;
577+
MutableTerm mutLhsTerm(lhsTerm);
578+
(void) System.simplify(mutLhsTerm, &lhsPath);
579+
580+
assert(mutLhsTerm == mutRhsTerm && "Terms should be joinable");
581+
lhsPath.invert();
582+
unificationPath.append(lhsPath);
555583
}
584+
585+
// All simplified substitutions are now on the primary stack. Collect them to
586+
// produce the new term.
587+
unificationPath.add(RewriteStep::forDecomposeConcrete(differenceID,
588+
/*inverse=*/true));
589+
590+
// We now have a unification path from T.[RHS] to T.[LHS] using the
591+
// newly-recorded induced rules. Close the loop with a path from
592+
// T.[RHS] to R.[LHS] via the concrete type rules being unified.
593+
buildRewritePathForUnifier(lhsRuleID, rhsRuleID, System, unificationPath);
594+
595+
// Record a rewrite loop at T.[LHS].
596+
MutableTerm basepoint(difference.BaseTerm);
597+
basepoint.add(difference.LHS);
598+
System.recordRewriteLoop(basepoint, unificationPath);
599+
600+
// Optimization: If the LHS rule applies to the entire base term and not
601+
// a suffix, mark it substitution-simplified so that we can skip recording
602+
// the same rewrite loop in concretelySimplifyLeftHandSideSubstitutions().
603+
auto &lhsRule = System.getRule(lhsRuleID);
604+
if (lhsRule.getRHS() == difference.BaseTerm)
605+
lhsRule.markSubstitutionSimplified();
556606
}
557607

558608
/// When a type parameter has two concrete types, we have to unify the

test/Generics/unify_concrete_types_1.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,4 @@ struct MergeTest<G : P1 & P2> {
2828
// CHECK: [P1:X] => { concrete_type: [concrete: Foo<τ_0_0, τ_0_1> with <[P1:Y1], [P1:Z1]>] }
2929
// CHECK: [P2:X] => { concrete_type: [concrete: Foo<τ_0_0, τ_0_1> with <[P2:Y2], [P2:Z2]>] }
3030
// CHECK: τ_0_0 => { conforms_to: [P1 P2] }
31-
// CHECK: τ_0_0.[P1:X] => { concrete_type: [concrete: Foo<τ_0_0, τ_0_1> with <τ_0_0.[P1:Y1], τ_0_0.[P1:Z1]>] }
3231
// CHECK: }

0 commit comments

Comments
 (0)