@@ -56,7 +56,9 @@ void HomotopyGenerator::findProtocolConformanceRules(
56
56
SmallVectorImpl<std::pair<MutableTerm, unsigned >> &inContext,
57
57
const RewriteSystem &system) const {
58
58
59
- MutableTerm term = Basepoint;
59
+ auto redundancyCandidates = Path.findRulesAppearingOnceInEmptyContext ();
60
+ if (redundancyCandidates.empty ())
61
+ return ;
60
62
61
63
for (const auto &step : Path) {
62
64
switch (step.Kind ) {
@@ -65,14 +67,46 @@ void HomotopyGenerator::findProtocolConformanceRules(
65
67
if (!rule.isProtocolConformanceRule ())
66
68
break ;
67
69
68
- if (!step.isInContext ()) {
69
- assert ( std::find (notInContext. begin (),
70
- notInContext. end (),
71
- step. RuleID ) == notInContext. end () &&
72
- " A conformance rule appears more than once without context? " );
70
+ if (!step.isInContext () &&
71
+ step. Inverse &&
72
+ std::find (redundancyCandidates. begin (),
73
+ redundancyCandidates. end (),
74
+ step. RuleID ) != redundancyCandidates. end ()) {
73
75
notInContext.push_back (step.RuleID );
74
- } else if (step.EndOffset == 0 ) {
75
- assert (step.StartOffset > 0 );
76
+ }
77
+
78
+ break ;
79
+ }
80
+
81
+ case RewriteStep::AdjustConcreteType:
82
+ break ;
83
+ }
84
+ }
85
+
86
+ if (notInContext.empty ())
87
+ return ;
88
+
89
+ if (notInContext.size () > 1 ) {
90
+ llvm::errs () << " Multiple conformance rules appear once without context:\n " ;
91
+ for (unsigned ruleID : notInContext)
92
+ llvm::errs () << system.getRule (ruleID) << " \n " ;
93
+ dump (llvm::errs (), system);
94
+ llvm::errs () << " \n " ;
95
+ abort ();
96
+ }
97
+
98
+ MutableTerm term = Basepoint;
99
+
100
+ for (const auto &step : Path) {
101
+ switch (step.Kind ) {
102
+ case RewriteStep::ApplyRewriteRule: {
103
+ const auto &rule = system.getRule (step.RuleID );
104
+ if (!rule.isProtocolConformanceRule ())
105
+ break ;
106
+
107
+ if (step.StartOffset > 0 &&
108
+ step.EndOffset == 0 &&
109
+ rule.getLHS ().back () == system.getRule (notInContext[0 ]).getLHS ().back ()) {
76
110
MutableTerm prefix (term.begin (), term.begin () + step.StartOffset );
77
111
inContext.emplace_back (prefix, step.RuleID );
78
112
}
@@ -86,8 +120,13 @@ void HomotopyGenerator::findProtocolConformanceRules(
86
120
step.apply (term, system);
87
121
}
88
122
89
- if (notInContext.size () == 1 && inContext.empty ()) {
90
- llvm::errs () << " A conformance rule not based on another conformance rule?\n " ;
123
+ if (inContext.empty ()) {
124
+ notInContext.clear ();
125
+ return ;
126
+ }
127
+
128
+ if (inContext.size () > 1 ) {
129
+ llvm::errs () << " Multiple candidate conformance rules in context?\n " ;
91
130
dump (llvm::errs (), system);
92
131
llvm::errs () << " \n " ;
93
132
abort ();
@@ -252,6 +291,8 @@ void RewriteSystem::computeCandidateConformancePaths(
252
291
unsigned ruleID = pair.second ;
253
292
llvm::dbgs () << " (#" << ruleID << " ) " << getRule (ruleID) << " \n " ;
254
293
}
294
+
295
+ llvm::dbgs () << " \n " ;
255
296
}
256
297
257
298
// Suppose a 3-cell contains a conformance rule (T.[P] => T) in an empty
@@ -354,43 +395,111 @@ bool RewriteSystem::isValidConformancePath(
354
395
return true ;
355
396
}
356
397
398
+ void RewriteSystem::dumpGeneratingConformanceEquation (
399
+ llvm::raw_ostream &out,
400
+ unsigned baseRuleID,
401
+ const std::vector<SmallVector<unsigned , 2 >> &paths) const {
402
+ out << getRule (baseRuleID).getLHS () << " := " ;
403
+
404
+ bool first = true ;
405
+ for (const auto &path : paths) {
406
+ if (!first)
407
+ out << " ∨ " ;
408
+ else
409
+ first = false ;
410
+ for (unsigned ruleID : path)
411
+ out << " (" << getRule (ruleID).getLHS () << " )" ;
412
+ }
413
+ }
414
+
415
+ void RewriteSystem::verifyGeneratingConformanceEquations (
416
+ const llvm::MapVector<unsigned ,
417
+ std::vector<SmallVector<unsigned , 2 >>>
418
+ &conformancePaths) const {
419
+ #ifndef NDEBUG
420
+ for (const auto &pair : conformancePaths) {
421
+ const auto &rule = getRule (pair.first );
422
+ auto *proto = rule.getLHS ().back ().getProtocol ();
423
+
424
+ MutableTerm baseTerm (rule.getLHS ());
425
+ (void ) simplify (baseTerm);
426
+
427
+ for (const auto &path : pair.second ) {
428
+ const auto &otherRule = getRule (path.back ());
429
+ auto *otherProto = otherRule.getLHS ().back ().getProtocol ();
430
+
431
+ if (proto != otherProto) {
432
+ llvm::errs () << " Invalid equation: " ;
433
+ dumpGeneratingConformanceEquation (llvm::errs (),
434
+ pair.first , pair.second );
435
+ llvm::errs () << " \n " ;
436
+ llvm::errs () << " Mismatched conformance:\n " ;
437
+ llvm::errs () << " Base rule: " << rule << " \n " ;
438
+ llvm::errs () << " Final rule: " << otherRule << " \n\n " ;
439
+ dump (llvm::errs ());
440
+ abort ();
441
+ }
442
+
443
+ MutableTerm otherTerm;
444
+ for (unsigned otherRuleID : path) {
445
+ otherTerm.append (getRule (otherRuleID).getLHS ());
446
+ }
447
+
448
+ (void ) simplify (otherTerm);
449
+
450
+ if (baseTerm != otherTerm) {
451
+ llvm::errs () << " Invalid equation: " ;
452
+ llvm::errs () << " \n " ;
453
+ dumpGeneratingConformanceEquation (llvm::errs (),
454
+ pair.first , pair.second );
455
+ llvm::errs () << " Invalid conformance path:\n " ;
456
+ llvm::errs () << " Expected: " << baseTerm << " \n " ;
457
+ llvm::errs () << " Got: " << otherTerm << " \n\n " ;
458
+ dump (llvm::errs ());
459
+ abort ();
460
+ }
461
+ }
462
+ }
463
+ #endif
464
+ }
465
+
357
466
// / Computes a minimal set of generating conformances, assuming that homotopy
358
467
// / reduction has already eliminated all redundant rewrite rules that are not
359
468
// / conformance rules.
360
469
void RewriteSystem::computeGeneratingConformances (
361
470
llvm::DenseSet<unsigned > &redundantConformances) {
362
471
llvm::MapVector<unsigned , std::vector<SmallVector<unsigned , 2 >>> conformancePaths;
363
472
473
+ // Prepare the initial set of equations: every non-redundant conformance rule
474
+ // can be expressed as itself.
364
475
for (unsigned ruleID : indices (Rules)) {
365
476
const auto &rule = getRule (ruleID);
366
- if (rule.isProtocolConformanceRule ()) {
367
- SmallVector<unsigned , 2 > path;
368
- path.push_back (ruleID);
369
- conformancePaths[ruleID].push_back (path);
370
- }
477
+ if (rule.isRedundant ())
478
+ continue ;
479
+
480
+ if (!rule.isProtocolConformanceRule ())
481
+ continue ;
482
+
483
+ SmallVector<unsigned , 2 > path;
484
+ path.push_back (ruleID);
485
+ conformancePaths[ruleID].push_back (path);
371
486
}
372
487
373
488
computeCandidateConformancePaths (conformancePaths);
374
489
375
490
if (Debug.contains (DebugFlags::GeneratingConformances)) {
376
491
llvm::dbgs () << " Initial set of equations:\n " ;
377
492
for (const auto &pair : conformancePaths) {
378
- llvm::dbgs () << " - " << getRule (pair.first ).getLHS () << " := " ;
379
-
380
- bool first = true ;
381
- for (const auto &path : pair.second ) {
382
- if (!first)
383
- llvm::dbgs () << " ∨ " ;
384
- else
385
- first = false ;
386
- for (unsigned ruleID : path)
387
- llvm::dbgs () << " (" << getRule (ruleID).getLHS () << " )" ;
388
- }
389
-
493
+ llvm::dbgs () << " - " ;
494
+ dumpGeneratingConformanceEquation (llvm::dbgs (),
495
+ pair.first , pair.second );
390
496
llvm::dbgs () << " \n " ;
391
497
}
392
498
}
393
499
500
+ verifyGeneratingConformanceEquations (conformancePaths);
501
+
502
+ // Find a minimal set of generating conformances.
394
503
for (const auto &pair : conformancePaths) {
395
504
for (const auto &path : pair.second ) {
396
505
llvm::SmallDenseSet<unsigned , 4 > visited;
@@ -404,6 +513,30 @@ void RewriteSystem::computeGeneratingConformances(
404
513
}
405
514
}
406
515
516
+ // Check invariants.
517
+ #ifndef NDEBUG
518
+ for (const auto &pair : conformancePaths) {
519
+ if (redundantConformances.count (pair.first ) > 0 )
520
+ continue ;
521
+
522
+ const auto &rule = getRule (pair.first );
523
+
524
+ if (rule.isRedundant ()) {
525
+ llvm::errs () << " Generating conformance is redundant: " ;
526
+ llvm::errs () << rule << " \n\n " ;
527
+ dump (llvm::errs ());
528
+ abort ();
529
+ }
530
+
531
+ if (rule.containsUnresolvedSymbols ()) {
532
+ llvm::errs () << " Generating conformance contains unresolved symbols: " ;
533
+ llvm::errs () << rule << " \n\n " ;
534
+ dump (llvm::errs ());
535
+ abort ();
536
+ }
537
+ }
538
+ #endif
539
+
407
540
if (Debug.contains (DebugFlags::GeneratingConformances)) {
408
541
llvm::dbgs () << " Generating conformances:\n " ;
409
542
0 commit comments