Skip to content

Commit 84c7188

Browse files
authored
Merge pull request #78526 from xedin/issue-78371
[CSOptimizer] Literal arguments should cause score reset only for operators
2 parents 18be5e8 + e3987be commit 84c7188

File tree

2 files changed

+33
-11
lines changed

2 files changed

+33
-11
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
@@ -527,10 +527,11 @@ static void determineBestChoicesInContext(
527527
// type matches a parameter type (i.e. when partially resolved generic
528528
// types are matched) this function is going to produce \c std::nullopt
529529
// instead of `0` that indicates "not a match".
530-
std::function<std::optional<double>(GenericSignature, Type, Type,
531-
MatchOptions)>
530+
std::function<std::optional<double>(GenericSignature, ValueDecl *, Type,
531+
Type, MatchOptions)>
532532
scoreCandidateMatch =
533-
[&](GenericSignature genericSig, Type candidateType, Type paramType,
533+
[&](GenericSignature genericSig, ValueDecl *choice,
534+
Type candidateType, Type paramType,
534535
MatchOptions options) -> std::optional<double> {
535536
auto areEqual = [&](Type a, Type b) {
536537
return a->getDesugaredType()->isEqual(b->getDesugaredType());
@@ -618,13 +619,12 @@ static void determineBestChoicesInContext(
618619

619620
if (!candidateOptionals.empty() || !paramOptionals.empty()) {
620621
if (paramOptionals.size() >= candidateOptionals.size()) {
621-
auto score = scoreCandidateMatch(genericSig, candidateType,
622+
auto score = scoreCandidateMatch(genericSig, choice, candidateType,
622623
paramType, options);
623624
// Injection lowers the score slightly to comply with
624625
// old behavior where exact matches on operator parameter
625626
// types were always preferred.
626-
return score == 1 && isOperatorDisjunction(disjunction) ? 0.9
627-
: score;
627+
return score == 1 && choice->isOperator() ? 0.9 : score;
628628
}
629629

630630
// Optionality mismatch.
@@ -746,7 +746,7 @@ static void determineBestChoicesInContext(
746746
// everything else the solver should try both concrete and
747747
// generic and disambiguate during ranking.
748748
if (result == CheckRequirementsResult::Success)
749-
return isOperatorDisjunction(disjunction) ? 0.9 : 1.0;
749+
return choice->isOperator() ? 0.9 : 1.0;
750750

751751
return 0;
752752
}
@@ -914,7 +914,7 @@ static void determineBestChoicesInContext(
914914
options |= MatchFlag::DisableCGFloatDoubleConversion;
915915

916916
auto candidateScore = scoreCandidateMatch(
917-
genericSig, candidateType, paramType, options);
917+
genericSig, decl, candidateType, paramType, options);
918918

919919
if (!candidateScore)
920920
continue;
@@ -958,7 +958,7 @@ static void determineBestChoicesInContext(
958958
// Preferring outer disjunction first works better in situations
959959
// when contextual type for the whole chain becomes available at
960960
// some point during solving at it would allow for faster pruning.
961-
if (score > 0 && onlyLiteralCandidates)
961+
if (score > 0 && onlyLiteralCandidates && decl->isOperator())
962962
score = 0.1;
963963

964964
// If one of the result types matches exactly, that's a good
@@ -984,7 +984,7 @@ static void determineBestChoicesInContext(
984984
->isCGFloat())
985985
return false;
986986

987-
return scoreCandidateMatch(genericSig,
987+
return scoreCandidateMatch(genericSig, decl,
988988
overloadType->getResult(),
989989
candidateResultTy,
990990
/*options=*/{}) > 0;

validation-test/Sema/issue78371.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// https://github.com/swiftlang/swift/issues/78371
4+
5+
// Note that the test has to use a standard operator because
6+
// custom ones are not optimized.
7+
8+
struct Scalar : Equatable {
9+
init(_: UInt8) {}
10+
init?(_: Int) {}
11+
}
12+
13+
func ==(_: Scalar, _: Scalar) -> Bool { }
14+
15+
extension Optional where Wrapped == Scalar {
16+
static func ==(_: Wrapped?, _: Wrapped?) -> Wrapped { }
17+
}
18+
19+
func test(a: Scalar) {
20+
let result = a == Scalar(0x07FD)
21+
let _: Scalar = result // Ok
22+
}

0 commit comments

Comments
 (0)