@@ -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.
529527void 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
0 commit comments