Skip to content

Commit 74537cf

Browse files
authored
Merge pull request #42608 from DougGregor/existential-sendable-warnings-5.7
Introduce missing Sendable conformances for existential conversions
2 parents b26108c + 1ff7fd9 commit 74537cf

File tree

6 files changed

+84
-15
lines changed

6 files changed

+84
-15
lines changed

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5433,7 +5433,7 @@ collectExistentialConformances(Type fromType, Type toType,
54335433
SmallVector<ProtocolConformanceRef, 4> conformances;
54345434
for (auto proto : layout.getProtocols()) {
54355435
conformances.push_back(TypeChecker::containsProtocol(
5436-
fromType, proto, module));
5436+
fromType, proto, module, false, /*allowMissing=*/true));
54375437
}
54385438

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

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7108,7 +7108,8 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifyConformsToConstraint(
71087108
case ConstraintKind::SelfObjectOfProtocol: {
71097109
auto conformance = TypeChecker::containsProtocol(
71107110
type, protocol, DC->getParentModule(),
7111-
/*skipConditionalRequirements=*/true);
7111+
/*skipConditionalRequirements=*/true,
7112+
/*allowMissing=*/true);
71127113
if (conformance) {
71137114
return recordConformance(conformance);
71147115
}

lib/Sema/TypeCheckProtocol.cpp

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

56735673
ProtocolConformanceRef
56745674
TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
5675-
bool skipConditionalRequirements) {
5675+
bool skipConditionalRequirements,
5676+
bool allowMissing) {
56765677
// Existential types don't need to conform, i.e., they only need to
56775678
// contain the protocol.
56785679
if (T->isExistentialType()) {
@@ -5694,8 +5695,9 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
56945695
if (auto superclass = layout.getSuperclass()) {
56955696
auto result =
56965697
(skipConditionalRequirements
5697-
? M->lookupConformance(superclass, Proto)
5698-
: TypeChecker::conformsToProtocol(superclass, Proto, M));
5698+
? M->lookupConformance(superclass, Proto, allowMissing)
5699+
: TypeChecker::conformsToProtocol(
5700+
superclass, Proto, M, allowMissing));
56995701
if (result) {
57005702
return result;
57015703
}
@@ -5713,13 +5715,22 @@ TypeChecker::containsProtocol(Type T, ProtocolDecl *Proto, ModuleDecl *M,
57135715
return ProtocolConformanceRef(Proto);
57145716
}
57155717

5718+
// FIXME: Unify with shouldCreateMissingConformances
5719+
if (allowMissing &&
5720+
Proto->isSpecificProtocol(KnownProtocolKind::Sendable)) {
5721+
return ProtocolConformanceRef(
5722+
M->getASTContext().getBuiltinConformance(
5723+
T, Proto, GenericSignature(), { },
5724+
BuiltinConformanceKind::Missing));
5725+
}
5726+
57165727
return ProtocolConformanceRef::forInvalid();
57175728
}
57185729

57195730
// For non-existential types, this is equivalent to checking conformance.
57205731
return (skipConditionalRequirements
5721-
? M->lookupConformance(T, Proto)
5722-
: TypeChecker::conformsToProtocol(T, Proto, M));
5732+
? M->lookupConformance(T, Proto, allowMissing)
5733+
: TypeChecker::conformsToProtocol(T, Proto, M, allowMissing));
57235734
}
57245735

57255736
ProtocolConformanceRef

lib/Sema/TypeChecker.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,8 @@ Expr *addImplicitLoadExpr(
791791
/// an empty optional.
792792
ProtocolConformanceRef containsProtocol(Type T, ProtocolDecl *Proto,
793793
ModuleDecl *M,
794-
bool skipConditionalRequirements=false);
794+
bool skipConditionalRequirements=false,
795+
bool allowMissing=false);
795796

796797
/// Determine whether the given type conforms to the given protocol.
797798
///

test/ClangImporter/objc_async.swift

Lines changed: 9 additions & 7 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() { }
@@ -314,6 +315,7 @@ func check() async {
314315
_ = await BazFrame(size: 0)
315316
}
316317

318+
@available(SwiftStdlib 5.5, *)
317319
func testSender(
318320
sender: NXSender,
319321
sendableObject: SendableClass,
@@ -325,7 +327,7 @@ func testSender(
325327
nonSendableGeneric: GenericObject<SendableClass>,
326328
ptr: UnsafeMutableRawPointer,
327329
stringArray: [String]
328-
) {
330+
) async {
329331
sender.sendAny(sendableObject)
330332
sender.sendAny(nonSendableObject)
331333
// expected-warning@-1 {{conformance of 'NonSendableClass' to 'Sendable' is unavailable}}
@@ -344,22 +346,22 @@ func testSender(
344346

345347
sender.sendProto(sendableProtos)
346348
sender.sendProto(nonSendableProtos)
347-
// expected-error@-1 {{argument type 'any LabellyProtocol & ObjCClub' does not conform to expected type 'Sendable'}}
348-
// FIXME(rdar://89992095): Should be a warning because we're in -warn-concurrency
349+
// expected-warning@-1 {{type 'any LabellyProtocol & ObjCClub' does not conform to the 'Sendable' protocol}}
349350

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

355355
sender.sendAnyArray([sendableObject])
356356
sender.sendAnyArray([nonSendableObject])
357357
// expected-warning@-1 {{conformance of 'NonSendableClass' to 'Sendable' is unavailable}}
358358

359359
sender.sendGeneric(sendableGeneric)
360+
// expected-warning@-1{{type 'GenericObject<SendableClass>' does not conform to the 'Sendable' protocol}}
361+
// FIXME: Shouldn't warn
362+
360363
sender.sendGeneric(nonSendableGeneric)
361-
// expected-error@-1 {{argument type 'GenericObject<SendableClass>' does not conform to expected type 'Sendable'}}
362-
// FIXME(rdar://89992095): Should be a warning because we're in -warn-concurrency
364+
// expected-warning@-1 {{type 'GenericObject<SendableClass>' does not conform to the 'Sendable' protocol}}
363365

364366
sender.sendPtr(ptr)
365367
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)