@@ -479,8 +479,13 @@ static Constraint *determineBestChoicesInContext(
479
479
480
480
if (!candidateOptionals.empty () || !paramOptionals.empty ()) {
481
481
if (paramOptionals.size () >= candidateOptionals.size ()) {
482
- return scoreCandidateMatch (genericSig, candidateType, paramType,
483
- options);
482
+ auto score = scoreCandidateMatch (genericSig, candidateType,
483
+ paramType, options);
484
+ // Injection lowers the score slightly to comply with
485
+ // old behavior where exact matches on operator parameter
486
+ // types were always preferred.
487
+ return score == 1 && isOperatorDisjunction (disjunction) ? 0.9
488
+ : score;
484
489
}
485
490
486
491
// Optionality mismatch.
@@ -512,26 +517,60 @@ static Constraint *determineBestChoicesInContext(
512
517
513
518
// Check protocol requirement(s) if this parameter is a
514
519
// generic parameter type.
515
- if (genericSig && paramType->isTypeParameter ()) {
516
- auto protocolRequirements = genericSig->getRequiredProtocols (paramType);
517
- // It's a generic parameter or dependent member which might
518
- // be connected via ame-type constraints to other generic
519
- // parameters or dependent member but we cannot check that here,
520
- // so let's add a tiny score just to acknowledge that it could
521
- // possibly match.
522
- if (protocolRequirements.empty ())
523
- return 0.01 ;
524
-
525
- if (llvm::all_of (protocolRequirements, [&](ProtocolDecl *protocol) {
526
- return bool (cs.lookupConformance (candidateType, protocol));
527
- })) {
528
- if (auto *GP = paramType->getAs <GenericTypeParamType>()) {
529
- auto *paramDecl = GP->getDecl ();
530
- if (paramDecl && paramDecl->isOpaqueType ())
531
- return 1.0 ;
520
+ if (genericSig && paramType->is <GenericTypeParamType>()) {
521
+ // If candidate is not fully resolved, check conformances only
522
+ // and lower the score.
523
+ if (candidateType->hasTypeVariable ()) {
524
+ auto protocolRequirements =
525
+ genericSig->getRequiredProtocols (paramType);
526
+ if (llvm::all_of (protocolRequirements, [&](ProtocolDecl *protocol) {
527
+ return bool (cs.lookupConformance (candidateType, protocol));
528
+ })) {
529
+ if (auto *GP = paramType->getAs <GenericTypeParamType>()) {
530
+ auto *paramDecl = GP->getDecl ();
531
+ if (paramDecl && paramDecl->isOpaqueType ())
532
+ return 1.0 ;
533
+ }
534
+ return 0.7 ;
532
535
}
533
- return 0.7 ;
536
+
537
+ return 0 ;
538
+ }
539
+
540
+ // If the candidate type is fully resolved, let's check all of
541
+ // the requirements that are associated with the corresponding
542
+ // parameter, if all of them are satisfied this candidate is
543
+ // an exact match.
544
+
545
+ auto isParameterType = [¶mType](Type type) {
546
+ return type->isEqual (paramType);
547
+ };
548
+
549
+ SmallVector<Requirement, 4 > requirements;
550
+ for (const auto &requirement : genericSig.getRequirements ()) {
551
+ if (requirement.getFirstType ().findIf (isParameterType) ||
552
+ (requirement.getKind () != RequirementKind::Layout &&
553
+ requirement.getSecondType ().findIf (isParameterType)))
554
+ requirements.push_back (requirement);
534
555
}
556
+
557
+ auto result = checkRequirements (
558
+ requirements,
559
+ [¶mType, &candidateType](SubstitutableType *type) -> Type {
560
+ if (type->isEqual (paramType))
561
+ return candidateType;
562
+ return ErrorType::get (type);
563
+ },
564
+ SubstOptions (std::nullopt));
565
+
566
+ // Concrete operator overloads are always more preferable to
567
+ // generic ones if there are exact or subtype matches, for
568
+ // everything else the solver should try both concrete and
569
+ // generic and disambiguate during ranking.
570
+ if (result == CheckRequirementsResult::Success)
571
+ return isOperatorDisjunction (disjunction) ? 0.9 : 1.0 ;
572
+
573
+ return 0 ;
535
574
}
536
575
537
576
// Parameter is generic, let's check whether top-level
0 commit comments