@@ -364,48 +364,29 @@ void PropertyMap::addSuperclassProperty(
364364 }
365365}
366366
367- // / Given two rules (V.[LHS] => V) and (V' .[RHS] => V'), build a rewrite
368- // / path from T.[RHS] to T.[LHS], where T is the longer of the two terms
369- // / V and V'.
370- static void buildRewritePathForUnifier ( unsigned lhsRuleID,
371- unsigned rhsRuleID ,
367+ // / Given a rule (V.[LHS] => V) and a rewrite path (T .[RHS] => T) where
368+ // / T == U.V, build a rewrite path from T.[RHS] to T.[LHS].
369+ static void buildRewritePathForUnifier (Term key,
370+ unsigned lhsRuleID,
371+ const RewritePath &rhsPath ,
372372 const RewriteSystem &system,
373- RewritePath & path) {
373+ RewritePath * path) {
374374 unsigned lhsLength = system.getRule (lhsRuleID).getRHS ().size ();
375- unsigned rhsLength = system.getRule (rhsRuleID).getRHS ().size ();
376-
377- unsigned lhsPrefix = 0 , rhsPrefix = 0 ;
378- if (lhsLength < rhsLength)
379- lhsPrefix = rhsLength - lhsLength;
380- if (rhsLength < lhsLength)
381- rhsPrefix = lhsLength - rhsLength;
382-
383- assert (lhsPrefix == 0 || rhsPrefix == 0 );
384-
385- // If the rule was actually (V.[RHS] => V) with T == U.V for some
386- // |U| > 0, strip U from the prefix of each substitution of [RHS].
387- if (rhsPrefix > 0 ) {
388- path.add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ rhsPrefix,
389- /* endOffset=*/ 0 ,
390- /* inverse=*/ true ));
391- }
375+ unsigned lhsPrefix = key.size () - lhsLength;
392376
393- // Apply the rule (V.[RHS] => V).
394- path.add (RewriteStep::forRewriteRule (
395- /* startOffset=*/ rhsPrefix, /* endOffset=*/ 0 ,
396- /* ruleID=*/ rhsRuleID, /* inverse=*/ false ));
377+ path->append (rhsPath);
397378
398- // Apply the inverted rule (V' => V' .[LHS]).
399- path. add (RewriteStep::forRewriteRule (
379+ // Apply the inverted rule U.(V => V.[LHS]).
380+ path-> add (RewriteStep::forRewriteRule (
400381 /* startOffset=*/ lhsPrefix, /* endOffset=*/ 0 ,
401382 /* ruleID=*/ lhsRuleID, /* inverse=*/ true ));
402383
403384 // If the rule was actually (V.[LHS] => V) with T == U.V for some
404385 // |U| > 0, prefix each substitution of [LHS] with U.
405386 if (lhsPrefix > 0 ) {
406- path. add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ lhsPrefix,
407- /* endOffset=*/ 0 ,
408- /* inverse=*/ false ));
387+ path-> add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ lhsPrefix,
388+ /* endOffset=*/ 0 ,
389+ /* inverse=*/ false ));
409390 }
410391}
411392
@@ -460,21 +441,39 @@ static void buildRewritePathForUnifier(unsigned lhsRuleID,
460441// / T, so T = U.V for some |U| > 0, (or vice versa). In this case we need
461442// / an additional step in the middle to prefix the concrete substitutions
462443// / of [LHS] (or [LHS]) with U.
463- static void buildRewritePathForInducedRule (unsigned differenceID,
444+ static void buildRewritePathForInducedRule (Term key,
445+ unsigned differenceID,
464446 unsigned lhsRuleID,
465- unsigned rhsRuleID ,
447+ const RewritePath &rhsPath ,
466448 unsigned substitutionIndex,
467449 const RewriteSystem &system,
468- RewritePath & path) {
450+ RewritePath * path) {
469451 // Replace f(Xn) with Xn and push T.[RHS] on the stack.
470- path. add (RewriteStep::forRightConcreteProjection (
452+ path-> add (RewriteStep::forRightConcreteProjection (
471453 differenceID, substitutionIndex, /* inverse=*/ false ));
472454
473- buildRewritePathForUnifier (lhsRuleID, rhsRuleID , system, path);
455+ buildRewritePathForUnifier (key, lhsRuleID, rhsPath , system, path);
474456
475457 // Pop T.[LHS] from the stack, leaving behind Xn.
476- path.add (RewriteStep::forLeftConcreteProjection (
477- differenceID, substitutionIndex, /* inverse=*/ true ));
458+ path->add (RewriteStep::forLeftConcreteProjection (
459+ differenceID, substitutionIndex, /* inverse=*/ true ));
460+ }
461+
462+ // / Given that LHS and RHS are known to simplify to the same term, build a
463+ // / rewrite path from RHS to LHS.
464+ static void buildPathJoiningTerms (MutableTerm lhsTerm,
465+ MutableTerm rhsTerm,
466+ RewriteSystem &system,
467+ RewritePath *path) {
468+ (void ) system.simplify (rhsTerm, path);
469+
470+ RewritePath lhsPath;
471+ (void ) system.simplify (lhsTerm, &lhsPath);
472+ lhsPath.invert ();
473+
474+ path->append (lhsPath);
475+
476+ assert (lhsTerm == rhsTerm);
478477}
479478
480479// / Given two concrete type rules (T.[LHS] => T) and (T.[RHS] => T) and
@@ -491,7 +490,7 @@ static void buildRewritePathForInducedRule(unsigned differenceID,
491490void PropertyMap::processTypeDifference (const TypeDifference &difference,
492491 unsigned differenceID,
493492 unsigned lhsRuleID,
494- unsigned rhsRuleID ) {
493+ const RewritePath &rhsPath ) {
495494 bool debug = Debug.contains (DebugFlags::ConcreteUnification);
496495
497496 if (debug) {
@@ -520,8 +519,9 @@ void PropertyMap::processTypeDifference(const TypeDifference &difference,
520519 auto rhsTerm = difference.getOriginalSubstitution (index);
521520
522521 RewritePath inducedRulePath;
523- buildRewritePathForInducedRule (differenceID, lhsRuleID, rhsRuleID,
524- index, System, inducedRulePath);
522+ buildRewritePathForInducedRule (difference.BaseTerm , differenceID,
523+ lhsRuleID, rhsPath, index,
524+ System, &inducedRulePath);
525525
526526 if (debug) {
527527 llvm::dbgs () << " %% Induced rule " << lhsTerm
@@ -531,19 +531,7 @@ void PropertyMap::processTypeDifference(const TypeDifference &difference,
531531 }
532532
533533 System.addRule (lhsTerm, rhsTerm, &inducedRulePath);
534-
535- // Build a path from rhsTerm (the original substitution) to
536- // lhsTerm (the replacement substitution).
537- MutableTerm mutRhsTerm (rhsTerm);
538- (void ) System.simplify (mutRhsTerm, &unificationPath);
539-
540- RewritePath lhsPath;
541- MutableTerm mutLhsTerm (lhsTerm);
542- (void ) System.simplify (mutLhsTerm, &lhsPath);
543-
544- assert (mutLhsTerm == mutRhsTerm && " Terms should be joinable" );
545- lhsPath.invert ();
546- unificationPath.append (lhsPath);
534+ buildPathJoiningTerms (lhsTerm, rhsTerm, System, &unificationPath);
547535 }
548536
549537 // All simplified substitutions are now on the primary stack. Collect them to
@@ -554,7 +542,8 @@ void PropertyMap::processTypeDifference(const TypeDifference &difference,
554542 // We now have a unification path from T.[RHS] to T.[LHS] using the
555543 // newly-recorded induced rules. Close the loop with a path from
556544 // T.[RHS] to R.[LHS] via the concrete type rules being unified.
557- buildRewritePathForUnifier (lhsRuleID, rhsRuleID, System, unificationPath);
545+ buildRewritePathForUnifier (difference.BaseTerm , lhsRuleID, rhsPath,
546+ System, &unificationPath);
558547
559548 // Record a rewrite loop at T.[LHS].
560549 MutableTerm basepoint (difference.BaseTerm );
@@ -635,33 +624,21 @@ void PropertyMap::unifyConcreteTypes(
635624 }
636625
637626 // This rule does not need a rewrite path because it will be related
638- // to the existing rule in concretelySimplifyLeftHandSideSubstitutions() .
627+ // to the two existing rules by the processTypeDifference() calls below .
639628 System.addRule (lhsTerm, rhsTerm);
640- }
641-
642- // Recover the (LHS ∧ RHS) rule.
643- RewritePath path;
644- bool simplified = System.simplify (lhsTerm, &path);
645- assert (simplified);
646- (void ) simplified;
647-
648- // FIXME: This is unsound! While 'key' was canonical at the time we
649- // started property map construction, we might have added other rules
650- // since then that made it non-canonical.
651- assert (path.size () == 1 );
652- assert (path.begin ()->Kind == RewriteStep::Rule);
653629
654- unsigned newRuleID = path.begin ()->getRuleID ();
630+ // Recover a rewrite path from T to T.[LHS ∧ RHS].
631+ RewritePath path;
632+ buildPathJoiningTerms (rhsTerm, lhsTerm, System, &path);
655633
656- // Process LHS -> (LHS ∧ RHS).
657- if (checkRulePairOnce (*existingRuleID, newRuleID))
634+ // Process LHS -> (LHS ∧ RHS).
658635 processTypeDifference (lhsDifference, *lhsDifferenceID,
659- *existingRuleID, newRuleID );
636+ *existingRuleID, path );
660637
661- // Process RHS -> (LHS ∧ RHS).
662- if (checkRulePairOnce (ruleID, newRuleID))
638+ // Process RHS -> (LHS ∧ RHS).
663639 processTypeDifference (rhsDifference, *rhsDifferenceID,
664- ruleID, newRuleID);
640+ ruleID, path);
641+ }
665642
666643 // The new property is more specific, so update ConcreteType and
667644 // ConcreteTypeRule.
@@ -679,9 +656,16 @@ void PropertyMap::unifyConcreteTypes(
679656 assert (*existingProperty == lhsDifference.LHS );
680657 assert (property == lhsDifference.RHS );
681658
682- if (checkRulePairOnce (*existingRuleID, ruleID))
659+ if (checkRulePairOnce (*existingRuleID, ruleID)) {
660+ // Build a rewrite path (T.[RHS] => T).
661+ RewritePath path;
662+ path.add (RewriteStep::forRewriteRule (
663+ /* startOffset=*/ 0 , /* endOffset=*/ 0 ,
664+ /* ruleID=*/ ruleID, /* inverse=*/ false ));
665+
683666 processTypeDifference (lhsDifference, *lhsDifferenceID,
684- *existingRuleID, ruleID);
667+ *existingRuleID, path);
668+ }
685669
686670 // The new property is more specific, so update existingProperty and
687671 // existingRuleID.
@@ -691,17 +675,32 @@ void PropertyMap::unifyConcreteTypes(
691675 return ;
692676 }
693677
694- // Handle the case where LHS == (LHS ∧ RHS) by processing LHS -> (LHS ∧ RHS).
678+ // Handle the case where LHS == (LHS ∧ RHS) by processing RHS -> (LHS ∧ RHS).
695679 if (rhsDifferenceID) {
696680 assert (!lhsDifferenceID);
697681
698682 const auto &rhsDifference = System.getTypeDifference (*rhsDifferenceID);
699683 assert (property == rhsDifference.LHS );
700684 assert (*existingProperty == rhsDifference.RHS );
701685
702- if (checkRulePairOnce (*existingRuleID, ruleID))
686+ if (checkRulePairOnce (*existingRuleID, ruleID)) {
687+ // Build a rewrite path (T.[LHS] => T).
688+ RewritePath path;
689+ unsigned lhsLength = System.getRule (*existingRuleID).getRHS ().size ();
690+ unsigned prefix = key.size () - lhsLength;
691+
692+ if (prefix > 0 ) {
693+ path.add (RewriteStep::forPrefixSubstitutions (
694+ prefix, /* endOffset=*/ 0 , /* inverse=*/ true ));
695+ }
696+
697+ path.add (RewriteStep::forRewriteRule (
698+ /* startOffset=*/ prefix, /* endOffset=*/ 0 ,
699+ /* ruleID=*/ *existingRuleID, /* inverse=*/ false ));
700+
703701 processTypeDifference (rhsDifference, *rhsDifferenceID,
704- ruleID, *existingRuleID);
702+ ruleID, path);
703+ }
705704
706705 // The new property is less specific, so existingProperty and existingRuleID
707706 // remain unchanged.
@@ -725,8 +724,13 @@ void PropertyMap::unifyConcreteTypes(
725724 //
726725 // Since the new rule appears without context, it becomes redundant.
727726 if (checkRulePairOnce (*existingRuleID, ruleID)) {
727+ RewritePath rhsPath;
728+ rhsPath.add (RewriteStep::forRewriteRule (
729+ /* startOffset=*/ 0 , /* endOffset=*/ 0 ,
730+ /* ruleID=*/ ruleID, /* inverse=*/ false ));
731+
728732 RewritePath path;
729- buildRewritePathForUnifier (*existingRuleID, ruleID , System, path);
733+ buildRewritePathForUnifier (key, *existingRuleID, rhsPath , System, & path);
730734 System.recordRewriteLoop (MutableTerm (rule.getLHS ()), path);
731735
732736 rule.markSubstitutionSimplified ();
0 commit comments