37
37
using namespace swift ;
38
38
using namespace rewriting ;
39
39
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
+
40
116
// / This method takes a concrete type that was derived from a concrete type
41
117
// / produced by RewriteSystemBuilder::getConcreteSubstitutionSchema(),
42
118
// / either by extracting a structural sub-component or performing a (Swift AST)
@@ -310,7 +386,7 @@ static std::pair<Symbol, bool> unifySuperclasses(
310
386
// / Returns the old conflicting rule ID if there was a conflict,
311
387
// / otherwise returns None.
312
388
Optional<unsigned > PropertyBag::addProperty (
313
- Symbol property, unsigned ruleID, RewriteContext &ctx ,
389
+ Symbol property, unsigned ruleID, RewriteSystem &system ,
314
390
SmallVectorImpl<InducedRule> &inducedRules,
315
391
bool debug) {
316
392
@@ -320,18 +396,41 @@ Optional<unsigned> PropertyBag::addProperty(
320
396
ConformsToRules.push_back (ruleID);
321
397
return None;
322
398
323
- case Symbol::Kind::Layout:
399
+ case Symbol::Kind::Layout: {
400
+ auto newLayout = property.getLayoutConstraint ();
401
+
324
402
if (!Layout) {
325
- Layout = property.getLayoutConstraint ();
403
+ // If we haven't seen a layout requirement before, just record it.
404
+ Layout = newLayout;
326
405
LayoutRule = ruleID;
327
406
} else {
407
+ // Otherwise, compute the intersection.
328
408
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 ())
331
413
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
+ }
332
430
}
333
431
334
432
return None;
433
+ }
335
434
336
435
case Symbol::Kind::Superclass: {
337
436
// FIXME: Also handle superclass vs concrete
@@ -342,7 +441,8 @@ Optional<unsigned> PropertyBag::addProperty(
342
441
} else {
343
442
assert (SuperclassRule.hasValue ());
344
443
auto pair = unifySuperclasses (*Superclass, property,
345
- ctx, inducedRules, debug);
444
+ system.getRewriteContext (),
445
+ inducedRules, debug);
346
446
Superclass = pair.first ;
347
447
bool conflict = pair.second ;
348
448
if (conflict)
@@ -359,7 +459,8 @@ Optional<unsigned> PropertyBag::addProperty(
359
459
} else {
360
460
assert (ConcreteTypeRule.hasValue ());
361
461
bool conflict = unifyConcreteTypes (*ConcreteType, property,
362
- ctx, inducedRules, debug);
462
+ system.getRewriteContext (),
463
+ inducedRules, debug);
363
464
if (conflict)
364
465
return ConcreteTypeRule;
365
466
}
0 commit comments