Skip to content

Commit e24d18c

Browse files
committed
[CSRanking] Specify whether specialization check allows missing conformances or not
We have two places where `CompareDeclSpecializationRequest` is used: - A performance optimization that compares two generic overloads; - Solution ranking that checks all of the selected overloads against another solution. The former can allow missing conformances and shouldn't prevent the solver from checking overloads that differ on `Sendable` (because there is no information about what is passed as arguments) but the latter, since it has a solution, should prefer Sendable overloads over non-Sendable ones if possible (i.e. `init<T: Sendable>(_: T)` is a subtype of `init<T>(_: T)`).
1 parent d0fae40 commit e24d18c

File tree

4 files changed

+27
-18
lines changed

4 files changed

+27
-18
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)

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
}

test/Concurrency/sendable_disambiguation.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@
77
do {
88
struct Test {
99
init<T: Sendable>(value: T) {}
10-
// expected-note@-1 {{found this candidate}}
1110
init<T>(value: T) {}
12-
// expected-note@-1 {{found this candidate}}
1311
}
1412

1513
struct SendableOnly {
@@ -23,8 +21,7 @@ do {
2321
}
2422

2523
func testSendable<T: Sendable>(v: T) {
26-
_ = Test(value: v)
27-
// expected-error@-1 {{ambiguous use of 'init(value:)'}}
24+
_ = Test(value: v) // Ok
2825
_ = SendableOnly(value: v) // Ok
2926
}
3027
}

0 commit comments

Comments
 (0)