Skip to content

Commit bc1390e

Browse files
committed
Introduce missing Sendable conformances for existential conversions
When performing conversions to an existential that involves Sendable, introducing missing conformances as needed to allow the type-check to succeed and then (later) they'll be diagnosed appropriately. Fixes rdar://89992095.
1 parent 95274f8 commit bc1390e

File tree

5 files changed

+75
-8
lines changed

5 files changed

+75
-8
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
///
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)