Skip to content

Commit 5bb8028

Browse files
committed
RequirementMachine: Factor out a utility for building a rewrite path unifying to concrete type rules
1 parent 7087617 commit 5bb8028

File tree

1 file changed

+49
-62
lines changed

1 file changed

+49
-62
lines changed

lib/AST/RequirementMachine/PropertyUnification.cpp

Lines changed: 49 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)