@@ -43,6 +43,15 @@ bool PropertyMap::checkRulePairOnce(unsigned firstRuleID,
4343// / Given a key T, a rule (V.[p1] => V) where T == U.V, and a property [p2]
4444// / where [p1] < [p2], record a rule (T.[p2] => T) that is induced by
4545// / the original rule (V.[p1] => V).
46+ // /
47+ // / This is used to define rewrite loops for relating pairs of rules where
48+ // / one implies another:
49+ // /
50+ // / - a more specific layout constraint implies a general layout constraint5
51+ // / - a superclass bound implies a layout constraint
52+ // / - a concrete type that is a class implies a superclass bound
53+ // / - a concrete type that is a class implies a layout constraint
54+ // /
4655static void recordRelation (Term key,
4756 unsigned lhsRuleID,
4857 Symbol rhsProperty,
@@ -391,7 +400,122 @@ void PropertyMap::addSuperclassProperty(
391400 }
392401}
393402
394- // / Record induced rules from the given type difference.
403+ // / Build a rewrite path for a rule induced by concrete type unification.
404+ // /
405+ // / Consider two concrete type rules (T.[LHS] => T) and (T.[RHS] => T), a
406+ // / TypeDifference describing the transformation from LHS to RHS, and the
407+ // / index of a substitution Xn from [C] which is transformed into its
408+ // / replacement f(Xn).
409+ // /
410+ // / The rewrite path should allow us to eliminate the induced rule
411+ // / (f(Xn) => Xn), so the induced rule will appear without context, and
412+ // / the concrete type rules (T.[LHS] => T) and (T.[RHS] => T) will appear
413+ // / in context.
414+ // /
415+ // / There are two cases:
416+ // /
417+ // / a) The substitution Xn remains a type parameter in [RHS], but becomes
418+ // / a canonical term Xn', so f(Xn) = Xn'.
419+ // /
420+ // / In the first case, the induced rule (Xn => Xn'), described by a
421+ // / rewrite path as follows:
422+ // /
423+ // / Xn
424+ // / Xn' T.[RHS] // RightConcreteProjection(n) pushes T.[RHS]
425+ // / Xn' T // Application of (T.[RHS] => T) in context
426+ // / Xn' T.[LHS] // Application of (T => T.[LHS]) in context
427+ // / Xn' // LeftConcreteProjection(n) pops T.[LHS]
428+ // /
429+ // / Now when this path is composed with a rewrite step for the inverted
430+ // / induced rule (Xn' => Xn), we get a rewrite loop at Xn in which the
431+ // / new rule appears in empty context.
432+ // /
433+ // / b) The substitution Xn becomes a concrete type [D] in [C'], so
434+ // / f(Xn) = Xn.[D].
435+ // /
436+ // / In the second case, the induced rule is (Xn.[D] => Xn), described
437+ // / by a rewrite path (going in the other direction) as follows:
438+ // /
439+ // / Xn
440+ // / Xn.[D] T.[RHS] // RightConcreteProjection(n) pushes T.[RHS]
441+ // / Xn.[D] T // Application of (T.[RHS] => T) in context
442+ // / Xn.[D] T.[LHS] // Application of (T => T.[LHS]) in context
443+ // / Xn.[D] // LeftConcreteProjection(n) pops T.[LHS]
444+ // /
445+ // / Now when this path is composed with a rewrite step for the induced
446+ // / rule (Xn.[D] => Xn), we get a rewrite loop at Xn in which the
447+ // / new rule appears in empty context.
448+ // /
449+ // / There is a minor complication; the concrete type rules T.[LHS] and
450+ // / T.[RHS] might actually be T.[LHS] and V.[RHS] where V is a suffix of
451+ // / T, so T = U.V for some |U| > 0, (or vice versa). In this case we need
452+ // / an additional step in the middle to prefix the concrete substitutions
453+ // / of [LHS] (or [LHS]) with U.
454+ static void buildRewritePathForInducedRule (unsigned differenceID,
455+ unsigned lhsRuleID,
456+ unsigned rhsRuleID,
457+ unsigned substitutionIndex,
458+ const RewriteSystem &system,
459+ 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+
471+ // Replace f(Xn) with Xn and push T.[RHS] on the stack.
472+ path.add (RewriteStep::forRightConcreteProjection (
473+ differenceID, substitutionIndex, /* inverse=*/ false ));
474+
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+ }
500+
501+ // Pop T.[LHS] from the stack, leaving behind Xn.
502+ path.add (RewriteStep::forLeftConcreteProjection (
503+ differenceID, substitutionIndex, /* inverse=*/ true ));
504+ }
505+
506+ // / Given two concrete type rules (T.[LHS] => T) and (T.[RHS] => T) and
507+ // / TypeDifference describing the transformation from LHS to RHS,
508+ // / record rules for transforming each substitution of LHS into a
509+ // / more canonical type parameter or concrete type from RHS.
510+ // /
511+ // / This also records rewrite paths relating induced rules to the original
512+ // / concrete type rules, since the concrete type rules imply the induced
513+ // / rules and make them redundant.
514+ // /
515+ // / The implication going in the other direction -- where one of the
516+ // / two concrete type rules together with the induced rules implies the
517+ // / other concrete type rule -- is recorded in
518+ // / concretelySimplifyLeftHandSideSubstitutions().
395519void PropertyMap::processTypeDifference (const TypeDifference &difference,
396520 unsigned differenceID,
397521 unsigned lhsRuleID,
@@ -402,34 +526,22 @@ void PropertyMap::processTypeDifference(const TypeDifference &difference,
402526 difference.dump (llvm::dbgs ());
403527 }
404528
405- for (const auto &pair : difference.SameTypes ) {
406- // Both sides are type parameters; add a same-type requirement.
407- auto lhsTerm = difference.getOriginalSubstitution (pair.first );
408- MutableTerm rhsTerm (pair.second );
529+ for (unsigned index : indices (difference.LHS .getSubstitutions ())) {
530+ auto lhsTerm = difference.getReplacementSubstitution (index);
531+ auto rhsTerm = difference.getOriginalSubstitution (index);
409532
410- if (debug) {
411- llvm::dbgs () << " %% Induced rule " << lhsTerm
412- << " == " << rhsTerm << " \n " ;
413- }
414-
415- // FIXME: Need a rewrite path here.
416- System.addRule (lhsTerm, rhsTerm);
417- }
418-
419- for (const auto &pair : difference.ConcreteTypes ) {
420- // A type parameter is equated with a concrete type; add a concrete
421- // type requirement.
422- auto rhsTerm = difference.getOriginalSubstitution (pair.first );
423- MutableTerm lhsTerm (rhsTerm);
424- lhsTerm.add (pair.second );
533+ RewritePath path;
534+ buildRewritePathForInducedRule (differenceID, lhsRuleID, rhsRuleID,
535+ index, System, path);
425536
426537 if (debug) {
427538 llvm::dbgs () << " %% Induced rule " << lhsTerm
428- << " == " << rhsTerm << " \n " ;
539+ << " => " << rhsTerm << " with path " ;
540+ path.dump (llvm::dbgs (), lhsTerm, System);
541+ llvm::dbgs () << " \n " ;
429542 }
430543
431- // FIXME: Need a rewrite path here.
432- System.addRule (lhsTerm, rhsTerm);
544+ System.addRule (lhsTerm, rhsTerm, &path);
433545 }
434546}
435547
@@ -676,6 +788,11 @@ void PropertyMap::addProperty(
676788 llvm_unreachable (" Bad symbol kind" );
677789}
678790
791+ // / Post-pass to handle unification and conflict checking between pairs of
792+ // / rules of different kinds:
793+ // /
794+ // / - concrete vs superclass
795+ // / - concrete vs layout
679796void PropertyMap::checkConcreteTypeRequirements () {
680797 bool debug = Debug.contains (DebugFlags::ConcreteUnification);
681798
0 commit comments