Skip to content

Commit b129d92

Browse files
authored
Merge pull request swiftlang#69549 from xedin/rdar-117227549
[ConstraintSystem] Rework overload ranking based on Sendable conformances
2 parents ca53be7 + dff5786 commit b129d92

File tree

6 files changed

+91
-14
lines changed

6 files changed

+91
-14
lines changed

include/swift/AST/TypeCheckRequests.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,7 +2658,8 @@ class SynthesizeDefaultInitRequest
26582658

26592659
class CompareDeclSpecializationRequest
26602660
: public SimpleRequest<CompareDeclSpecializationRequest,
2661-
bool(DeclContext *, ValueDecl *, ValueDecl *, bool),
2661+
bool(DeclContext *, ValueDecl *, ValueDecl *, bool,
2662+
bool),
26622663
RequestFlags::Cached> {
26632664
public:
26642665
using SimpleRequest::SimpleRequest;
@@ -2667,9 +2668,9 @@ class CompareDeclSpecializationRequest
26672668
friend SimpleRequest;
26682669

26692670
// Evaluation.
2670-
bool evaluate(Evaluator &evaluator, DeclContext *DC,
2671-
ValueDecl *VD1, ValueDecl *VD2,
2672-
bool dynamic) const;
2671+
bool evaluate(Evaluator &evaluator, DeclContext *DC, ValueDecl *VD1,
2672+
ValueDecl *VD2, bool dynamic,
2673+
bool allowMissingConformances) const;
26732674

26742675
public:
26752676
// Caching.

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ SWIFT_REQUEST(TypeChecker, ClassAncestryFlagsRequest,
4747
SWIFT_REQUEST(TypeChecker, IDEInspectionFileRequest,
4848
SourceFile *(ModuleDecl *), Cached, NoLocationInfo)
4949
SWIFT_REQUEST(TypeChecker, CompareDeclSpecializationRequest,
50-
bool (DeclContext *, ValueDecl *, ValueDecl *, bool), Cached,
51-
NoLocationInfo)
50+
bool (DeclContext *, ValueDecl *, ValueDecl *, bool, bool),
51+
Cached, NoLocationInfo)
5252
SWIFT_REQUEST(TypeChecker, ConditionalRequirementsRequest,
5353
ArrayRef<Requirement> (NormalProtocolConformance *),
5454
Cached, NoLocationInfo)

include/swift/Sema/ConstraintSystem.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,10 @@ enum ScoreKind: unsigned int {
984984
SK_ValueToPointerConversion,
985985
/// A closure/function conversion to an autoclosure parameter.
986986
SK_FunctionToAutoClosureConversion,
987+
/// A type with a missing conformance(s) that has be synthesized
988+
/// or diagnosed later, such types are allowed to appear in
989+
/// a valid solution.
990+
SK_MissingSynthesizableConformance,
987991
/// An unapplied reference to a function. The purpose of this
988992
/// score bit is to prune overload choices that are functions
989993
/// when a solution has already been found using property.
@@ -1159,6 +1163,9 @@ struct Score {
11591163

11601164
case SK_UnappliedFunction:
11611165
return "use of overloaded unapplied function";
1166+
1167+
case SK_MissingSynthesizableConformance:
1168+
return "type with missing synthesizable conformance";
11621169
}
11631170
}
11641171

lib/Sema/CSRanking.cpp

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -417,16 +417,18 @@ static bool paramIsIUO(const ValueDecl *decl, int paramNum) {
417417
/// "Specialized" is essentially a form of subtyping, defined below.
418418
static bool isDeclAsSpecializedAs(DeclContext *dc, ValueDecl *decl1,
419419
ValueDecl *decl2,
420-
bool isDynamicOverloadComparison = false) {
420+
bool isDynamicOverloadComparison = false,
421+
bool allowMissingConformances = true) {
421422
return evaluateOrDefault(decl1->getASTContext().evaluator,
422423
CompareDeclSpecializationRequest{
423-
dc, decl1, decl2, isDynamicOverloadComparison},
424+
dc, decl1, decl2, isDynamicOverloadComparison,
425+
allowMissingConformances},
424426
false);
425427
}
426428

427429
bool CompareDeclSpecializationRequest::evaluate(
428430
Evaluator &eval, DeclContext *dc, ValueDecl *decl1, ValueDecl *decl2,
429-
bool isDynamicOverloadComparison) const {
431+
bool isDynamicOverloadComparison, bool allowMissingConformances) const {
430432
auto &C = decl1->getASTContext();
431433
// Construct a constraint system to compare the two declarations.
432434
ConstraintSystem cs(dc, ConstraintSystemOptions());
@@ -759,9 +761,16 @@ bool CompareDeclSpecializationRequest::evaluate(
759761
// Solve the system.
760762
auto solution = cs.solveSingle(FreeTypeVariableBinding::Allow);
761763

762-
// Ban value-to-optional conversions.
763-
if (solution && solution->getFixedScore().Data[SK_ValueToOptional] == 0)
764-
return completeResult(true);
764+
if (solution) {
765+
auto score = solution->getFixedScore();
766+
767+
// Ban value-to-optional conversions and
768+
// missing conformances if they are disallowed.
769+
if (score.Data[SK_ValueToOptional] == 0 &&
770+
(allowMissingConformances ||
771+
score.Data[SK_MissingSynthesizableConformance] == 0))
772+
return completeResult(true);
773+
}
765774
}
766775

767776
// If the first function has fewer effective parameters than the
@@ -1121,12 +1130,14 @@ SolutionCompareResult ConstraintSystem::compareSolutions(
11211130
bool firstAsSpecializedAs = false;
11221131
bool secondAsSpecializedAs = false;
11231132
if (isDeclAsSpecializedAs(cs.DC, decl1, decl2,
1124-
isDynamicOverloadComparison)) {
1133+
isDynamicOverloadComparison,
1134+
/*allowMissingConformances=*/false)) {
11251135
score1 += weight;
11261136
firstAsSpecializedAs = true;
11271137
}
11281138
if (isDeclAsSpecializedAs(cs.DC, decl2, decl1,
1129-
isDynamicOverloadComparison)) {
1139+
isDynamicOverloadComparison,
1140+
/*allowMissingConformances=*/false)) {
11301141
score2 += weight;
11311142
secondAsSpecializedAs = true;
11321143
}

lib/Sema/CSSimplify.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8413,6 +8413,16 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
84138413
if (isConformanceUnavailable(conformance, loc))
84148414
increaseScore(SK_Unavailable, locator);
84158415

8416+
unsigned numMissing = 0;
8417+
conformance.forEachMissingConformance(DC->getParentModule(),
8418+
[&numMissing](auto *missing) {
8419+
++numMissing;
8420+
return false;
8421+
});
8422+
8423+
if (numMissing > 0)
8424+
increaseScore(SK_MissingSynthesizableConformance, locator, numMissing);
8425+
84168426
// This conformance may be conditional, in which case we need to consider
84178427
// those requirements as constraints too.
84188428
if (conformance.isConcrete()) {
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %target-swift-frontend %s -emit-sil -o /dev/null -verify -strict-concurrency=complete
2+
3+
// REQUIRES: concurrency
4+
// REQUIRES: asserts
5+
// REQUIRES: OS=macosx
6+
7+
do {
8+
struct Test {
9+
init<T: Sendable>(value: T) {}
10+
init<T>(value: T) {}
11+
}
12+
13+
struct SendableOnly {
14+
init<T: Sendable>(value: T) {}
15+
}
16+
17+
func testNonSendable<T>(v: T) { // expected-note {{consider making generic parameter 'T' conform to the 'Sendable' protocol}}
18+
_ = Test(value: v) // Ok (non-Sendable overload)
19+
_ = SendableOnly(value: v)
20+
// expected-warning@-1 {{type 'T' does not conform to the 'Sendable' protocol}}
21+
}
22+
23+
func testSendable<T: Sendable>(v: T) {
24+
_ = Test(value: v) // Ok
25+
_ = SendableOnly(value: v) // Ok
26+
}
27+
}
28+
29+
do {
30+
class K {
31+
func value() {}
32+
}
33+
34+
struct X {
35+
var fn: (Int) -> K
36+
func fn(_: Int) -> Int { 42 }
37+
}
38+
39+
func sendable<T>(_ fn: (Int) -> T) -> T { fn(42) }
40+
func sendable<T: Sendable>(_ fn: (Int) -> T) -> T { fn(0) }
41+
42+
func test(x: X) {
43+
let res = sendable(x.fn) // Ok (non-ambiguous and non-Sendable overload)
44+
res.value() // To make sure that previous expression picks a property
45+
let _: K = sendable(x.fn) // Ok (picks `sendable<T>` with a property)
46+
let _: Int = sendable(x.fn) // Ok (picks `sendable<T: Sendable>` with a method)
47+
}
48+
}

0 commit comments

Comments
 (0)