@@ -579,6 +579,32 @@ static PotentialArchetype *replaceSelfWithPotentialArchetype(
579
579
return selfPA;
580
580
}
581
581
582
+ // / Determine whether the given protocol requirement is self-derived when it
583
+ // / occurs within the requirement signature of its own protocol.
584
+ static bool isSelfDerivedProtocolRequirementInProtocol (
585
+ const RequirementSource *source,
586
+ ProtocolDecl *selfProto,
587
+ GenericSignatureBuilder &builder) {
588
+ assert (source->isProtocolRequirement ());
589
+
590
+ // This can only happen if the requirement points comes from the protocol
591
+ // itself.
592
+ if (source->getProtocolDecl () != selfProto) return false ;
593
+
594
+ // This only applies if the parent is not the anchor for computing the
595
+ // requirement signature. Anywhere else, we can use the protocol requirement.
596
+ if (source->parent ->kind == RequirementSource::RequirementSignatureSelf)
597
+ return false ;
598
+
599
+ // If the relative type of the protocol requirement itself is in the
600
+ // same equivalence class as what we've proven with this requirement,
601
+ // it's a self-derived requirement.
602
+ return
603
+ source->getAffectedPotentialArchetype ()->getEquivalenceClassIfPresent () ==
604
+ builder.resolveEquivalenceClass (source->getStoredType (),
605
+ ArchetypeResolutionKind::AlreadyKnown);
606
+ }
607
+
582
608
const RequirementSource *RequirementSource::getMinimalConformanceSource (
583
609
PotentialArchetype *currentPA,
584
610
ProtocolDecl *proto,
@@ -607,6 +633,7 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
607
633
};
608
634
609
635
bool sawProtocolRequirement = false ;
636
+ ProtocolDecl *requirementSignatureSelfProto = nullptr ;
610
637
611
638
PotentialArchetype *rootPA = nullptr ;
612
639
Optional<std::pair<const RequirementSource *, const RequirementSource *>>
@@ -625,14 +652,25 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
625
652
626
653
// The parent potential archetype must conform to the protocol in which
627
654
// this requirement resides. Add this constraint.
628
- auto startOfPath =
629
- addConstraint (parentPA, source->getProtocolDecl (), source->parent );
630
- if (!startOfPath) return false ;
655
+ if (auto startOfPath =
656
+ addConstraint (parentPA, source->getProtocolDecl (),
657
+ source->parent )) {
658
+ // We found a redundant subpath; record it and stop the algorithm.
659
+ assert (startOfPath != source->parent );
660
+ redundantSubpath = { startOfPath, source->parent };
661
+ return true ;
662
+ }
631
663
632
- // We found a redundant subpath; record it and stop the algorithm.
633
- assert (startOfPath != source->parent );
634
- redundantSubpath = { startOfPath, source->parent };
635
- return true ;
664
+ // If this is a self-derived protocol requirement, fail.
665
+ if (requirementSignatureSelfProto &&
666
+ isSelfDerivedProtocolRequirementInProtocol (
667
+ source,
668
+ requirementSignatureSelfProto,
669
+ *currentPA->getBuilder ()))
670
+ return true ;
671
+
672
+ // No redundancy thus far.
673
+ return false ;
636
674
}
637
675
638
676
case Parent:
@@ -645,12 +683,17 @@ const RequirementSource *RequirementSource::getMinimalConformanceSource(
645
683
case EquivalentType:
646
684
return false ;
647
685
686
+ case RequirementSignatureSelf:
687
+ // Note the protocol whose requirement signature the requirement is
688
+ // based on.
689
+ requirementSignatureSelfProto = source->getProtocolDecl ();
690
+ LLVM_FALLTHROUGH;
691
+
648
692
case Explicit:
649
693
case Inferred:
650
694
case QuietlyInferred:
651
695
case NestedTypeNameMatch:
652
696
case ConcreteTypeBinding:
653
- case RequirementSignatureSelf:
654
697
rootPA = parentPA;
655
698
return false ;
656
699
}
@@ -4712,7 +4755,8 @@ namespace {
4712
4755
template <typename T>
4713
4756
bool removeSelfDerived (std::vector<Constraint<T>> &constraints,
4714
4757
ProtocolDecl *proto,
4715
- bool dropDerivedViaConcrete = true ) {
4758
+ bool dropDerivedViaConcrete = true ,
4759
+ bool allCanBeSelfDerived = false ) {
4716
4760
bool anyDerivedViaConcrete = false ;
4717
4761
Optional<Constraint<T>> remainingConcrete;
4718
4762
SmallVector<Constraint<T>, 4 > minimalSources;
@@ -4780,7 +4824,8 @@ namespace {
4780
4824
if (constraints.empty () && remainingConcrete)
4781
4825
constraints.push_back (*remainingConcrete);
4782
4826
4783
- assert (!constraints.empty () && " All constraints were self-derived!" );
4827
+ assert ((!constraints.empty () || allCanBeSelfDerived) &&
4828
+ " All constraints were self-derived!" );
4784
4829
return anyDerivedViaConcrete;
4785
4830
}
4786
4831
} // end anonymous namespace
@@ -5536,7 +5581,8 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
5536
5581
5537
5582
// Remove self-derived constraints.
5538
5583
if (removeSelfDerived (constraints, /* proto=*/ nullptr ,
5539
- /* dropDerivedViaConcrete=*/ false ))
5584
+ /* dropDerivedViaConcrete=*/ false ,
5585
+ /* allCanBeSelfDerived=*/ true ))
5540
5586
anyDerivedViaConcrete = true ;
5541
5587
5542
5588
// Sort the constraints, so we get a deterministic ordering of diagnostics.
@@ -5633,7 +5679,9 @@ void GenericSignatureBuilder::checkSameTypeConstraints(
5633
5679
auto &constraints = entry.second ;
5634
5680
5635
5681
// Remove derived-via-concrete constraints.
5636
- (void )removeSelfDerived (constraints, /* proto=*/ nullptr );
5682
+ (void )removeSelfDerived (constraints, /* proto=*/ nullptr ,
5683
+ /* dropDerivedViaConcrete=*/ true ,
5684
+ /* allCanBeSelfDerived=*/ true );
5637
5685
}
5638
5686
}
5639
5687
0 commit comments