@@ -400,6 +400,51 @@ void PropertyMap::addSuperclassProperty(
400400 }
401401}
402402
403+ // / Given two rules (V.[LHS] => V) and (V'.[RHS] => V'), build a rewrite
404+ // / path from T.[RHS] to T.[LHS], where T is the longer of the two terms
405+ // / V and V'.
406+ static void buildRewritePathForUnifier (unsigned lhsRuleID,
407+ unsigned rhsRuleID,
408+ const RewriteSystem &system,
409+ RewritePath &path) {
410+ unsigned lhsLength = system.getRule (lhsRuleID).getRHS ().size ();
411+ unsigned rhsLength = system.getRule (rhsRuleID).getRHS ().size ();
412+
413+ unsigned lhsPrefix = 0 , rhsPrefix = 0 ;
414+ if (lhsLength < rhsLength)
415+ lhsPrefix = rhsLength - lhsLength;
416+ if (rhsLength < lhsLength)
417+ rhsPrefix = lhsLength - rhsLength;
418+
419+ assert (lhsPrefix == 0 || rhsPrefix == 0 );
420+
421+ // If the rule was actually (V.[RHS] => V) with T == U.V for some
422+ // |U| > 0, strip U from the prefix of each substitution of [RHS].
423+ if (rhsPrefix > 0 ) {
424+ path.add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ rhsPrefix,
425+ /* endOffset=*/ 0 ,
426+ /* inverse=*/ true ));
427+ }
428+
429+ // Apply the rule (V.[RHS] => V).
430+ path.add (RewriteStep::forRewriteRule (
431+ /* startOffset=*/ rhsPrefix, /* endOffset=*/ 0 ,
432+ /* ruleID=*/ rhsRuleID, /* inverse=*/ false ));
433+
434+ // Apply the inverted rule (V' => V'.[LHS]).
435+ path.add (RewriteStep::forRewriteRule (
436+ /* startOffset=*/ lhsPrefix, /* endOffset=*/ 0 ,
437+ /* ruleID=*/ lhsRuleID, /* inverse=*/ true ));
438+
439+ // If the rule was actually (V.[LHS] => V) with T == U.V for some
440+ // |U| > 0, prefix each substitution of [LHS] with U.
441+ if (lhsPrefix > 0 ) {
442+ path.add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ lhsPrefix,
443+ /* endOffset=*/ 0 ,
444+ /* inverse=*/ false ));
445+ }
446+ }
447+
403448// / Build a rewrite path for a rule induced by concrete type unification.
404449// /
405450// / Consider two concrete type rules (T.[LHS] => T) and (T.[RHS] => T), a
@@ -457,46 +502,11 @@ static void buildRewritePathForInducedRule(unsigned differenceID,
457502 unsigned substitutionIndex,
458503 const RewriteSystem &system,
459504 RewritePath &path) {
460- unsigned lhsLength = system.getRule (lhsRuleID).getRHS ().size ();
461- unsigned rhsLength = system.getRule (rhsRuleID).getRHS ().size ();
462-
463- unsigned lhsPrefix = 0 , rhsPrefix = 0 ;
464- if (lhsLength < rhsLength)
465- lhsPrefix = rhsLength - lhsLength;
466- if (rhsLength < lhsLength)
467- rhsPrefix = lhsLength - rhsLength;
468-
469- assert (lhsPrefix == 0 || rhsPrefix == 0 );
470-
471505 // Replace f(Xn) with Xn and push T.[RHS] on the stack.
472506 path.add (RewriteStep::forRightConcreteProjection (
473507 differenceID, substitutionIndex, /* inverse=*/ false ));
474508
475- // If the rule was actually (V.[RHS] => V) with T == U.V for some
476- // |U| > 0, strip U from the prefix of each substitution of [RHS].
477- if (rhsPrefix > 0 ) {
478- path.add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ rhsPrefix,
479- /* endOffset=*/ 0 ,
480- /* inverse=*/ true ));
481- }
482-
483- // Apply the rule (V.[RHS] => V).
484- path.add (RewriteStep::forRewriteRule (
485- /* startOffset=*/ rhsPrefix, /* endOffset=*/ 0 ,
486- /* ruleID=*/ rhsRuleID, /* inverse=*/ false ));
487-
488- // Apply the inverted rule (V' => V'.[LHS]).
489- path.add (RewriteStep::forRewriteRule (
490- /* startOffset=*/ lhsPrefix, /* endOffset=*/ 0 ,
491- /* ruleID=*/ lhsRuleID, /* inverse=*/ true ));
492-
493- // If the rule was actually (V.[LHS] => V) with T == U.V for some
494- // |U| > 0, prefix each substitution of [LHS] with U.
495- if (lhsPrefix > 0 ) {
496- path.add (RewriteStep::forPrefixSubstitutions (/* prefix=*/ lhsPrefix,
497- /* endOffset=*/ 0 ,
498- /* inverse=*/ false ));
499- }
509+ buildRewritePathForUnifier (lhsRuleID, rhsRuleID, system, path);
500510
501511 // Pop T.[LHS] from the stack, leaving behind Xn.
502512 path.add (RewriteStep::forLeftConcreteProjection (
@@ -718,33 +728,10 @@ void PropertyMap::addConcreteTypeProperty(
718728 //
719729 // Since the new rule appears without context, it becomes redundant.
720730 if (checkRulePairOnce (*props->ConcreteTypeRule , ruleID)) {
721- const auto &otherRule = System.getRule (*props->ConcreteTypeRule );
722- assert (otherRule.getRHS ().size () < key.size ());
723-
724- unsigned prefixLength = (key.size () - otherRule.getRHS ().size ());
725-
726- // Build a loop that rewrites U.V back into itself via the two rules,
727- // with a prefix substitutions step in the middle.
728731 RewritePath path;
729-
730- // Add a rewrite step U.(V => V.[concrete: G<...> with <X, Y>]).
731- path.add (RewriteStep::forRewriteRule (/* startOffset=*/ prefixLength,
732- /* endOffset=*/ 0 ,
733- *props->ConcreteTypeRule ,
734- /* inverse=*/ true ));
735-
736- // Add a rewrite step to prefix 'U' to the substitutions.
737- path.add (RewriteStep::forPrefixSubstitutions (/* length=*/ prefixLength,
738- /* endOffset=*/ 0 ,
739- /* inverse=*/ false ));
740-
741- // Add a rewrite step (U.V.[concrete: G<...> with <U.X, U.Y>] => U.V).
742- path.add (RewriteStep::forRewriteRule (/* startOffset=*/ 0 ,
743- /* endOffset=*/ 0 ,
744- ruleID,
745- /* inverse=*/ false ));
746-
747- System.recordRewriteLoop (MutableTerm (key), path);
732+ buildRewritePathForUnifier (*props->ConcreteTypeRule , ruleID, System,
733+ path);
734+ System.recordRewriteLoop (MutableTerm (rule.getLHS ()), path);
748735 }
749736 }
750737}
0 commit comments