3737using namespace swift ;
3838using namespace rewriting ;
3939
40+ unsigned RewriteSystem::recordRelation (Symbol lhs, Symbol rhs) {
41+ auto key = std::make_pair (lhs, rhs);
42+ auto found = RelationMap.find (key);
43+ if (found != RelationMap.end ())
44+ return found->second ;
45+
46+ unsigned index = Relations.size ();
47+ Relations.push_back (key);
48+ auto inserted = RelationMap.insert (std::make_pair (key, index));
49+ assert (inserted.second );
50+ (void ) inserted;
51+
52+ return index;
53+ }
54+
55+ RewriteSystem::Relation
56+ RewriteSystem::getRelation (unsigned index) const {
57+ return Relations[index];
58+ }
59+
60+ // / Given two property rules (T.[p1] => T) and (T.[p2] => T) where [p1] < [p2],
61+ // / record a rewrite loop that makes the second rule redundant from the first.
62+ static void recordRelation (unsigned lhsRuleID, unsigned rhsRuleID,
63+ RewriteSystem &system,
64+ SmallVectorImpl<InducedRule> &inducedRules,
65+ bool debug) {
66+ const auto &lhsRule = system.getRule (lhsRuleID);
67+ const auto &rhsRule = system.getRule (rhsRuleID);
68+
69+ auto lhsProperty = lhsRule.getLHS ().back ();
70+ auto rhsProperty = rhsRule.getLHS ().back ();
71+
72+ assert (lhsProperty.isProperty ());
73+ assert (rhsProperty.isProperty ());
74+ assert (lhsProperty.getKind () == rhsProperty.getKind ());
75+
76+ if (debug) {
77+ llvm::dbgs () << " %% Recording relation: " ;
78+ llvm::dbgs () << lhsRule.getLHS () << " < " << rhsProperty << " \n " ;
79+ }
80+
81+ unsigned relationID = system.recordRelation (lhsProperty, rhsProperty);
82+
83+ // / Build the following rewrite path:
84+ // /
85+ // / (T => T.[p1]).[p2] ⊗ T.Relation([p1].[p2] => [p1]) ⊗ (T.[p1] => T).
86+ // /
87+ RewritePath path;
88+
89+ // / Starting from T.[p2], the LHS rule in reverse to get T.[p1].[p2].
90+ path.add (RewriteStep::forRewriteRule (/* startOffset=*/ 0 ,
91+ /* endOffset=*/ 1 ,
92+ /* ruleID=*/ lhsRuleID,
93+ /* inverse=*/ true ));
94+
95+ // / T.Relation([p1].[p2] => [p1]).
96+ path.add (RewriteStep::forRelation (relationID, /* inverse=*/ false ));
97+
98+ // / (T.[p1] => T).
99+ path.add (RewriteStep::forRewriteRule (/* startOffset=*/ 0 ,
100+ /* endOffset=*/ 0 ,
101+ /* ruleID=*/ lhsRuleID,
102+ /* inverse=*/ false ));
103+
104+ // / Add the rule (T.[p2] => T) with the above rewrite path.
105+ // /
106+ // / Since a rule (T.[p2] => T) *already exists*, both sides of the new
107+ // / rule will simplify down to T, and the rewrite path will become a loop.
108+ // /
109+ // / This loop encodes the fact that (T.[p1] => T) makes (T.[p2] => T)
110+ // / redundant.
111+ inducedRules.emplace_back (MutableTerm (rhsRule.getLHS ()),
112+ MutableTerm (rhsRule.getRHS ()),
113+ path);
114+ }
115+
40116// / This method takes a concrete type that was derived from a concrete type
41117// / produced by RewriteSystemBuilder::getConcreteSubstitutionSchema(),
42118// / either by extracting a structural sub-component or performing a (Swift AST)
@@ -310,7 +386,7 @@ static std::pair<Symbol, bool> unifySuperclasses(
310386// / Returns the old conflicting rule ID if there was a conflict,
311387// / otherwise returns None.
312388Optional<unsigned > PropertyBag::addProperty (
313- Symbol property, unsigned ruleID, RewriteContext &ctx ,
389+ Symbol property, unsigned ruleID, RewriteSystem &system ,
314390 SmallVectorImpl<InducedRule> &inducedRules,
315391 bool debug) {
316392
@@ -320,18 +396,41 @@ Optional<unsigned> PropertyBag::addProperty(
320396 ConformsToRules.push_back (ruleID);
321397 return None;
322398
323- case Symbol::Kind::Layout:
399+ case Symbol::Kind::Layout: {
400+ auto newLayout = property.getLayoutConstraint ();
401+
324402 if (!Layout) {
325- Layout = property.getLayoutConstraint ();
403+ // If we haven't seen a layout requirement before, just record it.
404+ Layout = newLayout;
326405 LayoutRule = ruleID;
327406 } else {
407+ // Otherwise, compute the intersection.
328408 assert (LayoutRule.hasValue ());
329- Layout = Layout.merge (property.getLayoutConstraint ());
330- if (!Layout->isKnownLayout ())
409+ auto mergedLayout = Layout.merge (property.getLayoutConstraint ());
410+
411+ // If the intersection is invalid, we have a conflict.
412+ if (!mergedLayout->isKnownLayout ())
331413 return LayoutRule;
414+
415+ // If the intersection is equal to the existing layout requirement,
416+ // the new layout requirement is redundant.
417+ if (mergedLayout == Layout) {
418+ recordRelation (*LayoutRule, ruleID, system, inducedRules, debug);
419+
420+ // If the intersection is equal to the new layout requirement, the
421+ // existing layout requirement is redundant.
422+ } else if (mergedLayout == newLayout) {
423+ recordRelation (ruleID, *LayoutRule, system, inducedRules, debug);
424+ LayoutRule = ruleID;
425+ } else {
426+ llvm::errs () << " Arbitrary intersection of layout requirements is "
427+ << " supported yet\n " ;
428+ abort ();
429+ }
332430 }
333431
334432 return None;
433+ }
335434
336435 case Symbol::Kind::Superclass: {
337436 // FIXME: Also handle superclass vs concrete
@@ -342,7 +441,8 @@ Optional<unsigned> PropertyBag::addProperty(
342441 } else {
343442 assert (SuperclassRule.hasValue ());
344443 auto pair = unifySuperclasses (*Superclass, property,
345- ctx, inducedRules, debug);
444+ system.getRewriteContext (),
445+ inducedRules, debug);
346446 Superclass = pair.first ;
347447 bool conflict = pair.second ;
348448 if (conflict)
@@ -359,7 +459,8 @@ Optional<unsigned> PropertyBag::addProperty(
359459 } else {
360460 assert (ConcreteTypeRule.hasValue ());
361461 bool conflict = unifyConcreteTypes (*ConcreteType, property,
362- ctx, inducedRules, debug);
462+ system.getRewriteContext (),
463+ inducedRules, debug);
363464 if (conflict)
364465 return ConcreteTypeRule;
365466 }
0 commit comments