@@ -530,18 +530,22 @@ static void determineBestChoicesInContext(
530
530
scoreCandidateMatch =
531
531
[&](GenericSignature genericSig, Type candidateType, Type paramType,
532
532
MatchOptions options) -> std::optional<double > {
533
- auto areEqual = [&options](Type a, Type b) {
534
- // Double<->CGFloat implicit conversion support for literals
535
- // only since in this case the conversion might not result in
536
- // score penalty.
537
- if (options.contains (MatchFlag::Literal) &&
538
- ((a->isDouble () && b->isCGFloat ()) ||
539
- (a->isCGFloat () && b->isDouble ())))
540
- return true ;
541
-
533
+ auto areEqual = [&](Type a, Type b) {
542
534
return a->getDesugaredType ()->isEqual (b->getDesugaredType ());
543
535
};
544
536
537
+ // Allow CGFloat -> Double widening conversions between
538
+ // candidate argument types and parameter types. This would
539
+ // make sure that Double is always preferred over CGFloat
540
+ // when using literals and ranking supported disjunction
541
+ // choices. Narrowing conversion (Double -> CGFloat) should
542
+ // be delayed as much as possible.
543
+ if (options.contains (MatchFlag::OnParam)) {
544
+ if (candidateType->isCGFloat () && paramType->isDouble ()) {
545
+ return options.contains (MatchFlag::Literal) ? 0.2 : 0.9 ;
546
+ }
547
+ }
548
+
545
549
if (options.contains (MatchFlag::ExactOnly))
546
550
return areEqual (candidateType, paramType) ? 1 : 0 ;
547
551
@@ -559,12 +563,12 @@ static void determineBestChoicesInContext(
559
563
if (candidateType->isInt () &&
560
564
TypeChecker::conformsToKnownProtocol (
561
565
paramType, KnownProtocolKind::ExpressibleByIntegerLiteral))
562
- return 0.2 ;
566
+ return paramType-> isDouble () ? 0.2 : 0.3 ;
563
567
564
568
if (candidateType->isDouble () &&
565
569
TypeChecker::conformsToKnownProtocol (
566
570
paramType, KnownProtocolKind::ExpressibleByFloatLiteral))
567
- return 0.2 ;
571
+ return 0.3 ;
568
572
}
569
573
570
574
return 0 ;
@@ -916,6 +920,19 @@ static void determineBestChoicesInContext(
916
920
// with a lot of favored overloads because on the result type alone.
917
921
if (decl->isOperator () && !isStandardComparisonOperator (decl)) {
918
922
if (llvm::any_of (resultTypes, [&](const Type candidateResultTy) {
923
+ // Avoid increasing weight based on CGFloat result type
924
+ // match because that could require narrowing conversion
925
+ // in the arguments and that is always detrimental.
926
+ //
927
+ // For example, `has_CGFloat_param(1.0 + 2.0)` should use
928
+ // `+(_: Double, _: Double) -> Double` instead of
929
+ // `+(_: CGFloat, _: CGFloat) -> CGFloat` which would match
930
+ // parameter of `has_CGFloat_param` exactly but use a
931
+ // narrowing conversion for both literals.
932
+ if (candidateResultTy->lookThroughAllOptionalTypes ()
933
+ ->isCGFloat ())
934
+ return false ;
935
+
919
936
return scoreCandidateMatch (genericSig,
920
937
overloadType->getResult (),
921
938
candidateResultTy,
0 commit comments