@@ -350,35 +350,51 @@ bool RewriteSystem::isValidConformancePath(
350
350
llvm::SmallDenseSet<unsigned , 4 > &visited,
351
351
llvm::DenseSet<unsigned > &redundantConformances,
352
352
const llvm::SmallVectorImpl<unsigned > &path,
353
+ const llvm::MapVector<unsigned , SmallVector<unsigned , 2 >> &parentPaths,
353
354
const llvm::MapVector<unsigned ,
354
355
std::vector<SmallVector<unsigned , 2 >>>
355
356
&conformancePaths) const {
356
357
for (unsigned ruleID : path) {
357
358
if (visited.count (ruleID) > 0 )
358
359
return false ;
359
360
360
- if (!redundantConformances.count (ruleID))
361
- continue ;
362
-
363
- SWIFT_DEFER {
364
- visited.erase (ruleID);
365
- };
366
- visited.insert (ruleID);
361
+ if (redundantConformances.count (ruleID)) {
362
+ SWIFT_DEFER {
363
+ visited.erase (ruleID);
364
+ };
365
+ visited.insert (ruleID);
366
+
367
+ auto found = conformancePaths.find (ruleID);
368
+ assert (found != conformancePaths.end ());
369
+
370
+ bool foundValidConformancePath = false ;
371
+ for (const auto &otherPath : found->second ) {
372
+ if (isValidConformancePath (visited, redundantConformances, otherPath,
373
+ parentPaths, conformancePaths)) {
374
+ foundValidConformancePath = true ;
375
+ break ;
376
+ }
377
+ }
367
378
368
- auto found = conformancePaths.find (ruleID);
369
- assert (found != conformancePaths.end ());
379
+ if (!foundValidConformancePath)
380
+ return false ;
381
+ }
370
382
371
- bool foundValidConformancePath = false ;
372
- for (const auto &otherPath : found->second ) {
373
- if (isValidConformancePath (visited, redundantConformances,
374
- otherPath, conformancePaths)) {
375
- foundValidConformancePath = true ;
376
- break ;
383
+ auto found = parentPaths.find (ruleID);
384
+ if (found != parentPaths.end ()) {
385
+ SWIFT_DEFER {
386
+ visited.erase (ruleID);
387
+ };
388
+ visited.insert (ruleID);
389
+
390
+ // If 'req' is based on some other conformance requirement
391
+ // `T.[P.]A : Q', we want to make sure that we have a
392
+ // non-redundant derivation for 'T : P'.
393
+ if (!isValidConformancePath (visited, redundantConformances, found->second ,
394
+ parentPaths, conformancePaths)) {
395
+ return false ;
377
396
}
378
397
}
379
-
380
- if (!foundValidConformancePath)
381
- return false ;
382
398
}
383
399
384
400
return true ;
@@ -401,6 +417,13 @@ bool RewriteSystem::isValidRefinementPath(
401
417
return true ;
402
418
}
403
419
420
+ void RewriteSystem::dumpConformancePath (
421
+ llvm::raw_ostream &out,
422
+ const SmallVectorImpl<unsigned > &path) const {
423
+ for (unsigned ruleID : path)
424
+ out << " (" << getRule (ruleID).getLHS () << " )" ;
425
+ }
426
+
404
427
void RewriteSystem::dumpGeneratingConformanceEquation (
405
428
llvm::raw_ostream &out,
406
429
unsigned baseRuleID,
@@ -413,8 +436,8 @@ void RewriteSystem::dumpGeneratingConformanceEquation(
413
436
out << " ∨ " ;
414
437
else
415
438
first = false ;
416
- for ( unsigned ruleID : path)
417
- out << " ( " << getRule (ruleID). getLHS () << " ) " ;
439
+
440
+ dumpConformancePath ( out, path) ;
418
441
}
419
442
}
420
443
@@ -474,8 +497,22 @@ void RewriteSystem::verifyGeneratingConformanceEquations(
474
497
// / conformance rules.
475
498
void RewriteSystem::computeGeneratingConformances (
476
499
llvm::DenseSet<unsigned > &redundantConformances) {
500
+ // Maps a conformance rule to a conformance path deriving the subject type's
501
+ // base type. For example, consider the following conformance rule:
502
+ //
503
+ // T.[P:A].[Q:B].[R] => T.[P:A].[Q:B]
504
+ //
505
+ // The subject type is T.[P:A].[Q:B]; in order to derive the metadata, we need
506
+ // the witness table for T.[P:A] : [Q] first, by computing a conformance access
507
+ // path for the term T.[P:A].[Q], known as the 'parent path'.
508
+ llvm::MapVector<unsigned , SmallVector<unsigned , 2 >> parentPaths;
509
+
510
+ // Maps a conformance rule to a list of paths. Each path in the list is a unique
511
+ // derivation of the conformance in terms of other conformance rules.
477
512
llvm::MapVector<unsigned , std::vector<SmallVector<unsigned , 2 >>> conformancePaths;
478
513
514
+ // The set of conformance rules which are protocol refinements, that is rules of
515
+ // the form [P].[Q] => [P].
479
516
llvm::DenseSet<unsigned > protocolRefinements;
480
517
481
518
// Prepare the initial set of equations: every non-redundant conformance rule
@@ -492,8 +529,56 @@ void RewriteSystem::computeGeneratingConformances(
492
529
path.push_back (ruleID);
493
530
conformancePaths[ruleID].push_back (path);
494
531
495
- if (rule.isProtocolRefinementRule ())
532
+ if (rule.isProtocolRefinementRule ()) {
496
533
protocolRefinements.insert (ruleID);
534
+ continue ;
535
+ }
536
+
537
+ auto lhs = rule.getLHS ();
538
+
539
+ auto parentSymbol = lhs[lhs.size () - 2 ];
540
+
541
+ // The last element is a protocol symbol, because this is a conformance rule.
542
+ // The second to last symbol is either an associated type, protocol or generic
543
+ // parameter symbol.
544
+ switch (parentSymbol.getKind ()) {
545
+ case Symbol::Kind::AssociatedType: {
546
+ // If we have a rule of the form X.[P:Y].[Q] => X.[P:Y] wih non-empty X,
547
+ // then the parent type is X.[P].
548
+ if (lhs.size () == 2 )
549
+ continue ;
550
+
551
+ MutableTerm mutTerm (lhs.begin (), lhs.end () - 2 );
552
+ assert (!mutTerm.empty ());
553
+
554
+ const auto protos = parentSymbol.getProtocols ();
555
+ assert (protos.size () == 1 );
556
+
557
+ bool simplified = simplify (mutTerm);
558
+ assert (!simplified || rule.isSimplified ());
559
+ (void ) simplified;
560
+
561
+ mutTerm.add (Symbol::forProtocol (protos[0 ], Context));
562
+
563
+ // Get a conformance path for X.[P] and record it.
564
+ decomposeTermIntoConformanceRuleLeftHandSides (mutTerm, parentPaths[ruleID]);
565
+ continue ;
566
+ }
567
+
568
+ case Symbol::Kind::GenericParam:
569
+ case Symbol::Kind::Protocol:
570
+ // Don't record a parent path, since the parent type is trivial (either a
571
+ // generic parameter, or the protocol 'Self' type).
572
+ continue ;
573
+
574
+ case Symbol::Kind::Name:
575
+ case Symbol::Kind::Layout:
576
+ case Symbol::Kind::Superclass:
577
+ case Symbol::Kind::ConcreteType:
578
+ break ;
579
+ }
580
+
581
+ llvm_unreachable (" Bad symbol kind" );
497
582
}
498
583
499
584
computeCandidateConformancePaths (conformancePaths);
@@ -506,6 +591,13 @@ void RewriteSystem::computeGeneratingConformances(
506
591
pair.first , pair.second );
507
592
llvm::dbgs () << " \n " ;
508
593
}
594
+
595
+ llvm::dbgs () << " Parent paths:\n " ;
596
+ for (const auto &pair : parentPaths) {
597
+ llvm::dbgs () << " - " << getRule (pair.first ).getLHS () << " : " ;
598
+ dumpConformancePath (llvm::dbgs (), pair.second );
599
+ llvm::dbgs () << " \n " ;
600
+ }
509
601
}
510
602
511
603
verifyGeneratingConformanceEquations (conformancePaths);
@@ -523,8 +615,8 @@ void RewriteSystem::computeGeneratingConformances(
523
615
llvm::SmallDenseSet<unsigned , 4 > visited;
524
616
visited.insert (pair.first );
525
617
526
- if (isValidConformancePath (visited, redundantConformances,
527
- path , conformancePaths)) {
618
+ if (isValidConformancePath (visited, redundantConformances, path,
619
+ parentPaths , conformancePaths)) {
528
620
redundantConformances.insert (pair.first );
529
621
break ;
530
622
}
0 commit comments