@@ -555,11 +555,9 @@ static void determineBestChoicesInContext(
555
555
// Check protocol requirement(s) if this parameter is a
556
556
// generic parameter type.
557
557
if (genericSig && paramType->isTypeParameter ()) {
558
- // If candidate is not fully resolved or is matched against a
559
- // dependent member type (i.e. `Self.T`), let's check conformances
560
- // only and lower the score.
561
- if (candidateType->hasTypeVariable () ||
562
- paramType->is <DependentMemberType>()) {
558
+ // Light-weight check if cases where `checkRequirements` is not
559
+ // applicable.
560
+ auto checkProtocolRequirementsOnly = [&]() -> double {
563
561
auto protocolRequirements =
564
562
genericSig->getRequiredProtocols (paramType);
565
563
if (llvm::all_of (protocolRequirements, [&](ProtocolDecl *protocol) {
@@ -574,29 +572,64 @@ static void determineBestChoicesInContext(
574
572
}
575
573
576
574
return 0 ;
575
+ };
576
+
577
+ // If candidate is not fully resolved or is matched against a
578
+ // dependent member type (i.e. `Self.T`), let's check conformances
579
+ // only and lower the score.
580
+ if (candidateType->hasTypeVariable () ||
581
+ paramType->is <DependentMemberType>()) {
582
+ return checkProtocolRequirementsOnly ();
577
583
}
578
584
579
585
// Cannot match anything but generic type parameters here.
580
586
if (!paramType->is <GenericTypeParamType>())
581
587
return std::nullopt;
582
588
583
- // If the candidate type is fully resolved, let's check all of
584
- // the requirements that are associated with the corresponding
585
- // parameter, if all of them are satisfied this candidate is
586
- // an exact match.
587
-
588
- auto isParameterType = [¶mType](Type type) {
589
- return type->isEqual (paramType);
590
- };
591
-
589
+ bool hasUnsatisfiableRequirements = false ;
592
590
SmallVector<Requirement, 4 > requirements;
591
+
593
592
for (const auto &requirement : genericSig.getRequirements ()) {
594
- if (requirement.getFirstType ().findIf (isParameterType) ||
595
- (requirement.getKind () != RequirementKind::Layout &&
596
- requirement.getSecondType ().findIf (isParameterType)))
593
+ if (hasUnsatisfiableRequirements)
594
+ break ;
595
+
596
+ llvm::SmallPtrSet<GenericTypeParamType *, 2 > toExamine;
597
+
598
+ auto recordReferencesGenericParams = [&toExamine](Type type) {
599
+ type.visit ([&toExamine](Type innerTy) {
600
+ if (auto *GP = innerTy->getAs <GenericTypeParamType>())
601
+ toExamine.insert (GP);
602
+ });
603
+ };
604
+
605
+ recordReferencesGenericParams (requirement.getFirstType ());
606
+
607
+ if (requirement.getKind () != RequirementKind::Layout)
608
+ recordReferencesGenericParams (requirement.getSecondType ());
609
+
610
+ if (llvm::any_of (toExamine, [&](GenericTypeParamType *GP) {
611
+ return paramType->isEqual (GP);
612
+ })) {
597
613
requirements.push_back (requirement);
614
+ // If requirement mentions other generic parameters
615
+ // `checkRequirements` would because we don't have
616
+ // candidate substitutions for anything but the current
617
+ // parameter type.
618
+ hasUnsatisfiableRequirements |= toExamine.size () > 1 ;
619
+ }
598
620
}
599
621
622
+ // If some of the requirements cannot be satisfied, because
623
+ // they reference other generic parameters, for example:
624
+ // `<T, U, where T.Element == U.Element>`, let's perform a
625
+ // light-weight check instead of skipping this overload choice.
626
+ if (hasUnsatisfiableRequirements)
627
+ return checkProtocolRequirementsOnly ();
628
+
629
+ // If the candidate type is fully resolved, let's check all of
630
+ // the requirements that are associated with the corresponding
631
+ // parameter, if all of them are satisfied this candidate is
632
+ // an exact match.
600
633
auto result = checkRequirements (
601
634
requirements,
602
635
[¶mType, &candidateType](SubstitutableType *type) -> Type {
0 commit comments