Skip to content

Commit 2fdd4b6

Browse files
committed
[CSOptimizer] Allow literal arguments to match parameters that conform to ExpressibleBy{Integer, Float}Literal
`scoreCandidateMatch` needs to reflect the fact that literal can assume any type that conforms to `ExpressibleBy{Integer, Float}Literal` protocol but since such bindings are non-default and alway produce a worse solution vs. default literal types if all of the arguments are literals let's use only exact matches otherwise there is a chance of "over-favoring" and creating more work for ranking.
1 parent 9b62c84 commit 2fdd4b6

File tree

2 files changed

+30
-2
lines changed

2 files changed

+30
-2
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,22 @@ static Constraint *determineBestChoicesInContext(
481481
}
482482

483483
if (options.contains(MatchFlag::Literal)) {
484+
// Integer and floating-point literals can match any parameter
485+
// type that conforms to `ExpressibleBy{Integer, Float}Literal`
486+
// protocol but since that would constitute a non-default binding
487+
// the score has to be slightly lowered.
488+
if (!paramType->hasTypeParameter()) {
489+
if (candidateType->isInt() &&
490+
TypeChecker::conformsToKnownProtocol(
491+
paramType, KnownProtocolKind::ExpressibleByIntegerLiteral))
492+
return 0.2;
493+
494+
if (candidateType->isDouble() &&
495+
TypeChecker::conformsToKnownProtocol(
496+
paramType, KnownProtocolKind::ExpressibleByFloatLiteral))
497+
return 0.2;
498+
}
499+
484500
return 0;
485501
}
486502

@@ -634,7 +650,10 @@ static Constraint *determineBestChoicesInContext(
634650
if (!matchings)
635651
return;
636652

637-
bool favorExactMatchesOnly = false;
653+
// If all of the arguments are literals, let's prioritize exact
654+
// matches to filter out non-default literal bindings which otherwise
655+
// could cause "over-favoring".
656+
bool favorExactMatchesOnly = onlyLiteralCandidates;
638657
// Preserves old behavior where for unary calls to members
639658
// the solver would not consider choices that didn't match on
640659
// the number of parameters (regardless of defaults) and only
@@ -812,7 +831,7 @@ static Constraint *determineBestChoicesInContext(
812831
[&resultTy](const auto &param) {
813832
return param.getPlainType()->isEqual(resultTy);
814833
}))
815-
score += 0.001;
834+
score += 0.1;
816835
}
817836

818837
favoredChoices.push_back({choice, score});

test/Constraints/old_hack_related_ambiguities.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,12 @@ do {
237237
assert(s.isEmpty, "") // Ok
238238
}
239239
}
240+
241+
extension Double {
242+
public static func * (left: Float, right: Double) -> Double { 0 }
243+
}
244+
245+
func test_non_default_literal_use(arg: Float) {
246+
let v = arg * 2.0 // shouldn't use `(Float, Double) -> Double` overload
247+
let _: Float = v // Ok
248+
}

0 commit comments

Comments
 (0)