Skip to content

Commit 5f2b790

Browse files
authored
Merge pull request #42606 from DougGregor/existential-sendable-warnings
Introduce missing Sendable conformances for existential conversions
2 parents 76445b9 + 001db3a commit 5f2b790

File tree

6 files changed

+85
-16
lines changed

6 files changed

+85
-16
lines changed

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5401,7 +5401,7 @@ collectExistentialConformances(Type fromType, Type toType,
54015401
SmallVector<ProtocolConformanceRef, 4> conformances;
54025402
for (auto proto : layout.getProtocols()) {
54035403
conformances.push_back(TypeChecker::containsProtocol(
5404-
fromType, proto, module));
5404+
fromType, proto, module, false, /*allowMissing=*/true));
54055405
}
54065406

54075407
return toType->getASTContext().AllocateCopy(conformances);

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7106,7 +7106,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
71067106
case ConstraintKind::SelfObjectOfProtocol: {
71077107
auto conformance = TypeChecker::containsProtocol(
71087108
type, protocol, DC->getParentModule(),
7109-
/*skipConditionalRequirements=*/true);
7109+
/*skipConditionalRequirements=*/true,
7110+
/*allowMissing=*/true);
71107111
if (conformance) {
71117112
return recordConformance(conformance);
71127113
}

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5538,7 +5538,8 @@ void ConformanceChecker::emitDelayedDiags() {
55385538

55395539
ProtocolConformanceRef
55405540
TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
5541-
bool skipConditionalRequirements) {
5541+
bool skipConditionalRequirements,
5542+
bool allowMissing) {
55425543
// Existential types don't need to conform, i.e., they only need to
55435544
// contain the protocol.
55445545
if (T->isExistentialType()) {
@@ -5560,8 +5561,9 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
55605561
if (auto superclass = layout.getSuperclass()) {
55615562
auto result =
55625563
(skipConditionalRequirements
5563-
? M->lookupConformance(superclass, Proto)
5564-
: TypeChecker::conformsToProtocol(superclass, Proto, M));
5564+
? M->lookupConformance(superclass, Proto, allowMissing)
5565+
: TypeChecker::conformsToProtocol(
5566+
superclass, Proto, M, allowMissing));
55655567
if (result) {
55665568
return result;
55675569
}
@@ -5579,13 +5581,22 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
55795581
return ProtocolConformanceRef(Proto);
55805582
}
55815583

5584+
// FIXME: Unify with shouldCreateMissingConformances
5585+
if (allowMissing &&
5586+
Proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
5587+
return ProtocolConformanceRef(
5588+
M->getASTContext().getBuiltinConformance(
5589+
T, Proto, GenericSignature(), { },
5590+
BuiltinConformanceKind::Missing));
5591+
}
5592+
55825593
return ProtocolConformanceRef::forInvalid();
55835594
}
55845595

55855596
// For non-existential types, this is equivalent to checking conformance.
55865597
return (skipConditionalRequirements
5587-
? M->lookupConformance(T, Proto)
5588-
: TypeChecker::conformsToProtocol(T, Proto, M));
5598+
? M->lookupConformance(T, Proto, allowMissing)
5599+
: TypeChecker::conformsToProtocol(T, Proto, M, allowMissing));
55895600
}
55905601

55915602
ProtocolConformanceRef

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,8 @@ Expr *addImplicitLoadExpr(
788788
/// an empty optional.
789789
ProtocolConformanceRef containsProtocol(Type T, ProtocolDecl *Proto,
790790
ModuleDecl *M,
791-
bool skipConditionalRequirements=false);
791+
bool skipConditionalRequirements=false,
792+
bool allowMissing=false);
792793

793794
/// Determine whether the given type conforms to the given protocol.
794795
///

test/ClangImporter/objc_async.swift

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// REQUIRES: concurrency
55
import Foundation
66
import ObjCConcurrency
7+
// expected-remark@-1{{add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'ObjCConcurrency'}}
78

89
@available(SwiftStdlib 5.5, *)
910
@MainActor func onlyOnMainActor() { }
@@ -322,6 +323,7 @@ func check() async {
322323
_ = await BazFrame(size: 0)
323324
}
324325

326+
@available(SwiftStdlib 5.5, *)
325327
func testSender(
326328
sender: NXSender,
327329
sendableObject: SendableClass,
@@ -333,7 +335,7 @@ func testSender(
333335
nonSendableGeneric: GenericObject<SendableClass>,
334336
ptr: UnsafeMutableRawPointer,
335337
stringArray: [String]
336-
) {
338+
) async {
337339
sender.sendAny(sendableObject)
338340
sender.sendAny(nonSendableObject)
339341
// expected-warning@-1 {{conformance of 'NonSendableClass' to 'Sendable' is unavailable}}
@@ -352,22 +354,22 @@ func testSender(
352354

353355
sender.sendProto(sendableProtos)
354356
sender.sendProto(nonSendableProtos)
355-
// expected-error@-1 {{argument type 'any LabellyProtocol & ObjCClub' does not conform to expected type 'Sendable'}}
356-
// FIXME(rdar://89992095): Should be a warning because we're in -warn-concurrency
357+
// expected-warning@-1 {{type 'any LabellyProtocol & ObjCClub' does not conform to the 'Sendable' protocol}}
357358

358359
sender.sendProtos(sendableProtos)
359360
sender.sendProtos(nonSendableProtos)
360-
// expected-error@-1 {{argument type 'any LabellyProtocol & ObjCClub' does not conform to expected type 'Sendable'}}
361-
// FIXME(rdar://89992095): Should be a warning because we're in -warn-concurrency
361+
// expected-warning@-1 {{type 'any LabellyProtocol & ObjCClub' does not conform to the 'Sendable' protocol}}
362362

363363
sender.sendAnyArray([sendableObject])
364364
sender.sendAnyArray([nonSendableObject])
365-
// expected-warning@-1 {{conformance of 'NonSendableClass' to 'Sendable' is unavailable}}
365+
// expected-warning@-1 {{conformance of 'NonSendableClass' to 'Sendable' is unavailable; this is an error in Swift 6}}
366366

367367
sender.sendGeneric(sendableGeneric)
368+
// expected-warning@-1{{type 'GenericObject<SendableClass>' does not conform to the 'Sendable' protocol}}
369+
// FIXME: Shouldn't warn
370+
368371
sender.sendGeneric(nonSendableGeneric)
369-
// expected-error@-1 {{argument type 'GenericObject<SendableClass>' does not conform to expected type 'Sendable'}}
370-
// FIXME(rdar://89992095): Should be a warning because we're in -warn-concurrency
372+
// expected-warning@-1 {{type 'GenericObject<SendableClass>' does not conform to the 'Sendable' protocol}}
371373

372374
sender.sendPtr(ptr)
373375
sender.sendStringArray(stringArray)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %target-typecheck-verify-swift -strict-concurrency=targeted
2+
// REQUIRES: concurrency
3+
// REQUIRES: OS=macosx
4+
5+
@preconcurrency func send(_: Sendable) { }
6+
func sendOpt(_: Sendable?) { }
7+
8+
enum E {
9+
case something(Sendable)
10+
}
11+
12+
@available(SwiftStdlib 5.1, *)
13+
func testE(a: Any, aOpt: Any?) async {
14+
send(a) // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
15+
sendOpt(a) // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
16+
sendOpt(aOpt) // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
17+
18+
let _: E = .something(a) // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
19+
_ = E.something(a) // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
20+
21+
var sendable: Sendable
22+
sendable = a // expected-warning{{type 'Any' does not conform to the 'Sendable' protocol}}
23+
24+
var arrayOfSendable: [Sendable]
25+
arrayOfSendable = [a, a] // expected-warning 2{{type 'Any' does not conform to the 'Sendable' protocol}}
26+
27+
func localFunc() { }
28+
sendable = localFunc // expected-warning{{type '() -> ()' does not conform to the 'Sendable' protocol}}
29+
// expected-note@-1{{a function type must be marked '@Sendable' to conform to 'Sendable'}}
30+
31+
_ = sendable
32+
_ = arrayOfSendable
33+
}
34+
35+
func testESilently(a: Any, aOpt: Any?) {
36+
send(a)
37+
sendOpt(a)
38+
sendOpt(aOpt)
39+
40+
let _: E = .something(a)
41+
_ = E.something(a)
42+
43+
var sendable: Sendable
44+
sendable = a
45+
46+
var arrayOfSendable: [Sendable]
47+
arrayOfSendable = [a, a]
48+
49+
func localFunc() { }
50+
sendable = localFunc
51+
52+
_ = sendable
53+
_ = arrayOfSendable
54+
}

0 commit comments

Comments
 (0)