Skip to content

Commit e280569

Browse files
committed
[CSOptimizer] Fix scoring while matching against partially resolved parameter types
When matching candidate like `[Int]` against `Array<Element>` we need to conservatively assume that if the nominals match the argument is a viable exact match because otherwise it's possible to skip some of the valid matches when other overload choice have generic parameters at the same parameter position.
1 parent 1dab584 commit e280569

File tree

2 files changed

+54
-3
lines changed

2 files changed

+54
-3
lines changed

lib/Sema/CSOptimizer.cpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,13 +1354,25 @@ static void determineBestChoicesInContext(
13541354
// types match i.e. Array<Element> as a parameter.
13551355
//
13561356
// This is slightly better than all of the conformances matching
1357-
// because the parameter is concrete and could split the graph.
1357+
// because the parameter is concrete and could split the system.
13581358
if (paramType->hasTypeParameter()) {
13591359
auto *candidateDecl = candidateType->getAnyNominal();
13601360
auto *paramDecl = paramType->getAnyNominal();
13611361

1362-
if (candidateDecl && paramDecl && candidateDecl == paramDecl)
1363-
return 0.8;
1362+
// Conservatively we need to make sure that this is not worse
1363+
// than matching against a generic parameter with or without
1364+
// requirements.
1365+
if (candidateDecl && paramDecl && candidateDecl == paramDecl) {
1366+
// If the candidate it not yet fully resolved, let's lower the
1367+
// score slightly to avoid over-favoring generic overload choices.
1368+
if (candidateType->hasTypeVariable())
1369+
return 0.8;
1370+
1371+
// If the candidate is fully resolved we need to treat this
1372+
// as we would generic parameter otherwise there is a risk
1373+
// of skipping some of the valid choices.
1374+
return choice->isOperator() ? 0.9 : 1.0;
1375+
}
13641376
}
13651377

13661378
return 0;
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
protocol ScalarOrArray {
4+
}
5+
6+
protocol SpecialValue: ScalarOrArray {
7+
}
8+
9+
extension Array: ScalarOrArray where Element: SpecialValue {
10+
}
11+
12+
struct CustomArray : ScalarOrArray {
13+
}
14+
15+
extension CustomArray : ExpressibleByArrayLiteral {
16+
public init(arrayLiteral elements: Int32...) {
17+
self.init()
18+
}
19+
}
20+
21+
extension Int32: SpecialValue {
22+
}
23+
24+
func +<T: ScalarOrArray>(_: T, _: CustomArray) -> CustomArray {}
25+
func +<T: ScalarOrArray>(_: CustomArray, _: T) -> CustomArray {}
26+
func +(_: CustomArray, _: CustomArray) -> CustomArray {}
27+
28+
extension Sequence where Element == Int {
29+
var asInt32: [Int32] { [] }
30+
}
31+
32+
extension Array where Element == Int {
33+
var asInt32: [Int32] { [] }
34+
}
35+
36+
func test(v: Int32, b: [Int]) -> [Int32] {
37+
let result = [1, v - v] + b.asInt32
38+
return result // Ok
39+
}

0 commit comments

Comments
 (0)