@@ -479,8 +479,13 @@ static Constraint *determineBestChoicesInContext(
479479
480480 if (!candidateOptionals.empty () || !paramOptionals.empty ()) {
481481 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;
484489 }
485490
486491 // Optionality mismatch.
@@ -512,26 +517,60 @@ static Constraint *determineBestChoicesInContext(
512517
513518 // Check protocol requirement(s) if this parameter is a
514519 // 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 ;
532535 }
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);
534555 }
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 ;
535574 }
536575
537576 // Parameter is generic, let's check whether top-level
0 commit comments