@@ -67,95 +67,6 @@ Symbol Symbol::prependPrefixToConcreteSubstitutions(
67
67
}, ctx);
68
68
}
69
69
70
- // / Check if this term overlaps with \p other for the purposes
71
- // / of the Knuth-Bendix completion algorithm.
72
- // /
73
- // / An overlap occurs if one of the following two cases holds:
74
- // /
75
- // / 1) If this == TUV and other == U.
76
- // / 2) If this == TU and other == UV.
77
- // /
78
- // / In both cases, we return the subterms T and V, together with
79
- // / an 'overlap kind' identifying the first or second case.
80
- // /
81
- // / If both rules have identical left hand sides, either case could
82
- // / apply, but we arbitrarily pick case 1.
83
- // /
84
- // / Note that this relation is not commutative; we need to check
85
- // / for overlap between both (X and Y) and (Y and X).
86
- OverlapKind
87
- Term::checkForOverlap (Term other,
88
- MutableTerm &t,
89
- MutableTerm &v) const {
90
- if (*this == other) {
91
- // If this term is equal to the other term, we have an overlap.
92
- t = MutableTerm ();
93
- v = MutableTerm ();
94
- return OverlapKind::First;
95
- }
96
-
97
- if (size () > other.size ()) {
98
- // If this term is longer than the other term, check if it contains
99
- // the other term.
100
- auto first1 = begin ();
101
- while (first1 <= end () - other.size ()) {
102
- if (std::equal (other.begin (), other.end (), first1)) {
103
- // We have an overlap.
104
- t = MutableTerm (begin (), first1);
105
- v = MutableTerm (first1 + other.size (), end ());
106
-
107
- // If both T and V are empty, we have two equal terms, which
108
- // should have been handled above.
109
- assert (!t.empty () || !v.empty ());
110
- assert (t.size () + other.size () + v.size () == size ());
111
-
112
- return OverlapKind::First;
113
- }
114
-
115
- ++first1;
116
- }
117
- }
118
-
119
- // Finally, check if a suffix of this term is equal to a prefix of
120
- // the other term.
121
- unsigned count = std::min (size (), other.size ());
122
- auto first1 = end () - count;
123
- auto last2 = other.begin () + count;
124
-
125
- // Initial state, depending on size() <=> other.size():
126
- //
127
- // ABC -- count = 3, first1 = this[0], last2 = other[3]
128
- // XYZ
129
- //
130
- // ABC -- count = 2, first1 = this[1], last2 = other[2]
131
- // XY
132
- //
133
- // ABC -- count = 3, first1 = this[0], last2 = other[3]
134
- // XYZW
135
-
136
- // Advance by 1, since we don't need to check for full containment
137
- ++first1;
138
- --last2;
139
-
140
- while (last2 != other.begin ()) {
141
- if (std::equal (other.begin (), last2, first1)) {
142
- t = MutableTerm (begin (), first1);
143
- v = MutableTerm (last2, other.end ());
144
-
145
- assert (!t.empty ());
146
- assert (!v.empty ());
147
- assert (t.size () + other.size () - v.size () == size ());
148
-
149
- return OverlapKind::Second;
150
- }
151
-
152
- ++first1;
153
- --last2;
154
- }
155
-
156
- return OverlapKind::None;
157
- }
158
-
159
70
// / If we have two symbols [P:T] and [Q:T], produce a merged symbol:
160
71
// /
161
72
// / - If P inherits from Q, this is just [P:T].
@@ -359,7 +270,9 @@ void RewriteSystem::processMergedAssociatedTypes() {
359
270
MergedAssociatedTypes.clear ();
360
271
}
361
272
362
- // / Compute a critical pair from two rewrite rules.
273
+ // / Compute a critical pair from the left hand sides of two rewrite rules,
274
+ // / where \p rhs begins at \p from, which must be an iterator pointing
275
+ // / into \p lhs.
363
276
// /
364
277
// / There are two cases:
365
278
// /
@@ -388,15 +301,11 @@ void RewriteSystem::processMergedAssociatedTypes() {
388
301
// / concrete substitution 'X' to get 'A.X'; the new concrete term
389
302
// / is now rooted at the same level as A.B in the rewrite system,
390
303
// / not just B.
391
- Optional<std::pair<MutableTerm, MutableTerm>>
392
- RewriteSystem::computeCriticalPair (const Rule &lhs, const Rule &rhs) const {
393
- MutableTerm t, v;
394
-
395
- switch (lhs.checkForOverlap (rhs, t, v)) {
396
- case OverlapKind::None:
397
- return None;
398
-
399
- case OverlapKind::First: {
304
+ std::pair<MutableTerm, MutableTerm>
305
+ RewriteSystem::computeCriticalPair (ArrayRef<Symbol>::const_iterator from,
306
+ const Rule &lhs, const Rule &rhs) const {
307
+ auto end = lhs.getLHS ().end ();
308
+ if (from + rhs.getLHS ().size () < end) {
400
309
// lhs == TUV -> X, rhs == U -> Y.
401
310
402
311
// Note: This includes the case where the two rules have exactly
@@ -405,31 +314,31 @@ RewriteSystem::computeCriticalPair(const Rule &lhs, const Rule &rhs) const {
405
314
// In this case, T and V are both empty.
406
315
407
316
// Compute the term TYV.
317
+ MutableTerm t (lhs.getLHS ().begin (), from);
408
318
t.append (rhs.getRHS ());
409
- t.append (v );
319
+ t.append (from + rhs. getLHS (). size (), lhs. getLHS (). end () );
410
320
return std::make_pair (MutableTerm (lhs.getRHS ()), t);
411
- }
412
-
413
- case OverlapKind::Second: {
321
+ } else {
414
322
// lhs == TU -> X, rhs == UV -> Y.
415
323
416
- if (v.back ().isSuperclassOrConcreteType ()) {
417
- v.back () = v.back ().prependPrefixToConcreteSubstitutions (
418
- t, Context);
419
- }
324
+ // Compute the term T.
325
+ MutableTerm t (lhs.getLHS ().begin (), from);
420
326
421
327
// Compute the term XV.
422
- MutableTerm xv;
423
- xv.append (lhs.getRHS ());
424
- xv.append (v);
328
+ MutableTerm xv (lhs.getRHS ());
329
+ xv.append (rhs.getLHS ().begin () + (lhs.getLHS ().end () - from),
330
+ rhs.getLHS ().end ());
331
+
332
+ if (xv.back ().isSuperclassOrConcreteType ()) {
333
+ xv.back () = xv.back ().prependPrefixToConcreteSubstitutions (
334
+ t, Context);
335
+ }
425
336
426
337
// Compute the term TY.
427
338
t.append (rhs.getRHS ());
339
+
428
340
return std::make_pair (xv, t);
429
341
}
430
- }
431
-
432
- llvm_unreachable (" Bad overlap kind" );
433
342
}
434
343
435
344
// / Computes the confluent completion using the Knuth-Bendix algorithm.
@@ -448,64 +357,97 @@ RewriteSystem::computeConfluentCompletion(unsigned maxIterations,
448
357
unsigned maxDepth) {
449
358
unsigned steps = 0 ;
450
359
451
- // The worklist must be processed in first-in-first-out order, to ensure
452
- // that we resolve all overlaps among the initial set of rules before
453
- // moving on to overlaps between rules introduced by completion.
454
- while (!Worklist.empty ()) {
455
- // Check if we've already done too much work.
456
- if (Rules.size () > maxIterations)
457
- return std::make_pair (CompletionResult::MaxIterations, steps);
458
-
459
- auto next = Worklist.front ();
460
- Worklist.pop_front ();
461
-
462
- const auto &lhs = Rules[next.first ];
463
- const auto &rhs = Rules[next.second ];
464
-
465
- if (DebugCompletion) {
466
- llvm::dbgs () << " $ Check for overlap: (#" << next.first << " ) " ;
467
- llvm::dbgs () << lhs << " \n " ;
468
- llvm::dbgs () << " -vs- (#" << next.second << " ) " ;
469
- llvm::dbgs () << rhs << " :\n " ;
470
- }
360
+ bool again = false ;
361
+
362
+ do {
363
+ std::vector<std::pair<MutableTerm, MutableTerm>> resolvedCriticalPairs;
364
+
365
+ // For every rule, looking for other rules that overlap with this rule.
366
+ for (unsigned i = 0 , e = Rules.size (); i < e; ++i) {
367
+ const auto &lhs = Rules[i];
368
+ if (lhs.isDeleted ())
369
+ continue ;
370
+
371
+ // Look up every suffix of this rule in the trie using findAll(). This
372
+ // will find both kinds of overlap:
373
+ //
374
+ // 1) rules whose left hand side is fully contained in [from,to)
375
+ // 2) rules whose left hand side has a prefix equal to [from,to)
376
+ auto from = lhs.getLHS ().begin ();
377
+ auto to = lhs.getLHS ().end ();
378
+ while (from < to) {
379
+ Trie.findAll (from, to, [&](unsigned j) {
380
+ // We don't have to consider the same pair of rules more than once,
381
+ // since those critical pairs were already resolved.
382
+ if (!CheckedOverlaps.insert (std::make_pair (i, j)).second )
383
+ return ;
384
+
385
+ const auto &rhs = Rules[j];
386
+ if (rhs.isDeleted ())
387
+ return ;
388
+
389
+ if (from == lhs.getLHS ().begin ()) {
390
+ // While every rule will have an overlap of the first kind
391
+ // with itself, it's not useful to consider since the
392
+ // resulting trivial pair is always trivial.
393
+ if (i == j)
394
+ return ;
395
+
396
+ // If the first rule's left hand side is a proper prefix
397
+ // of the second rule's left hand side, don't do anything.
398
+ //
399
+ // We will find the 'opposite' overlap later, where the two
400
+ // rules are swapped around. Then it becomes an overlap of
401
+ // the first kind, and will be handled as such.
402
+ if (rhs.getLHS ().size () > lhs.getLHS ().size ())
403
+ return ;
404
+ }
471
405
472
- auto pair = computeCriticalPair (lhs, rhs);
473
- if (!pair) {
474
- if (DebugCompletion) {
475
- llvm::dbgs () << " no overlap\n\n " ;
476
- }
477
- continue ;
478
- }
406
+ // Try to repair the confluence violation by adding a new rule.
407
+ resolvedCriticalPairs.push_back (computeCriticalPair (from, lhs, rhs));
479
408
480
- MutableTerm first, second;
409
+ if (DebugCompletion) {
410
+ const auto &pair = resolvedCriticalPairs.back ();
481
411
482
- // We have a critical pair (X, Y).
483
- std::tie (first, second) = *pair;
412
+ llvm::dbgs () << " $ Overlapping rules: (#" << i << " ) " ;
413
+ llvm::dbgs () << lhs << " \n " ;
414
+ llvm::dbgs () << " -vs- (#" << j << " ) " ;
415
+ llvm::dbgs () << rhs << " :\n " ;
416
+ llvm::dbgs () << " $$ First term of critical pair is "
417
+ << pair.first << " \n " ;
418
+ llvm::dbgs () << " $$ Second term of critical pair is "
419
+ << pair.second << " \n\n " ;
420
+ }
421
+ });
484
422
485
- if (DebugCompletion) {
486
- llvm::dbgs () << " $$ First term of critical pair is " << first << " \n " ;
487
- llvm::dbgs () << " $$ Second term of critical pair is " << second << " \n\n " ;
423
+ ++from;
424
+ }
488
425
}
489
- unsigned i = Rules.size ();
490
426
491
- // Try to repair the confluence violation by adding a new rule
492
- // X == Y.
493
- if (!addRule (first, second))
494
- continue ;
427
+ again = false ;
428
+ for (const auto &pair : resolvedCriticalPairs) {
429
+ // Check if we've already done too much work.
430
+ if (Rules.size () > maxIterations)
431
+ return std::make_pair (CompletionResult::MaxIterations, steps);
495
432
496
- // Only count a 'step' once we add a new rule.
497
- ++steps ;
433
+ if (! addRule (pair. first , pair. second ))
434
+ continue ;
498
435
499
- const auto &newRule = Rules[i];
500
- if (newRule .getDepth () > maxDepth)
501
- return std::make_pair (CompletionResult::MaxDepth, steps);
436
+ // Check if the new rule is too long.
437
+ if (Rules. back () .getDepth () > maxDepth)
438
+ return std::make_pair (CompletionResult::MaxDepth, steps);
502
439
503
- // If this new rule merges any associated types, process the merge now
440
+ // Only count a 'step' once we add a new rule.
441
+ ++steps;
442
+ again = true ;
443
+ }
444
+
445
+ // If the added rules merged any associated types, process the merges now
504
446
// before we continue with the completion procedure. This is important
505
447
// to perform incrementally since merging is required to repair confluence
506
448
// violations.
507
449
processMergedAssociatedTypes ();
508
- }
450
+ } while (again);
509
451
510
452
return std::make_pair (CompletionResult::Success, steps);
511
453
}
0 commit comments