Skip to content

Commit 0314ad8

Browse files
committed
[TypeChecker] Limit ObjC requirement concurrency stripping to Swift < 6 without strict concurrency enabled
1 parent 7f84ba4 commit 0314ad8

File tree

4 files changed

+291
-6
lines changed

4 files changed

+291
-6
lines changed

lib/Sema/TypeCheckProtocol.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1173,7 +1173,17 @@ swift::matchWitness(WitnessChecker::RequirementEnvironmentCache &reqEnvCache,
11731173
// which means that we need to maintain status quo to avoid breaking
11741174
// witness matching by stripping everything concurrency related from
11751175
// inner types.
1176-
if (req->isObjC()) {
1176+
auto shouldStripConcurrency = [&]() {
1177+
if (!req->isObjC())
1178+
return false;
1179+
1180+
auto &ctx = dc->getASTContext();
1181+
return !(ctx.isSwiftVersionAtLeast(6) ||
1182+
ctx.LangOpts.StrictConcurrencyLevel ==
1183+
StrictConcurrency::Complete);
1184+
};
1185+
1186+
if (shouldStripConcurrency()) {
11771187
if (reqType->is<FunctionType>()) {
11781188
auto *fnTy = reqType->castTo<FunctionType>();
11791189
SmallVector<AnyFunctionType::Param, 4> params;

test/Concurrency/sendable_objc_attr_in_type_context.swift renamed to test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \
66
// RUN: -import-objc-header %t/src/Test.h \
7-
// RUN: -strict-concurrency=complete \
7+
// RUN: -swift-version 5 \
88
// RUN: -enable-experimental-feature SendableCompletionHandlers \
99
// RUN: -module-name main -I %t -verify
1010

@@ -101,15 +101,11 @@ func test_sendable_attr_in_type_context(test: Test) {
101101

102102
_ = TestWithSendableID<SendableValue>() // Ok
103103

104-
// TOOD(diagnostics): Duplicate diagnostics
105104
TestWithSendableID().add(MyValue())
106-
// expected-warning@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
107105

108106
TestWithSendableSuperclass().add(SendableMyValue()) // Ok
109107

110-
// TOOD(diagnostics): Duplicate diagnostics
111108
TestWithSendableSuperclass().add(MyValue())
112-
// expected-warning@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
113109
}
114110

115111
class TestConformanceWithStripping : InnerSendableTypes {
@@ -119,3 +115,15 @@ class TestConformanceWithStripping : InnerSendableTypes {
119115
func test(withCallback name: String, handler: @escaping @MainActor ([String : Any], (any Error)?) -> Void) { // Ok
120116
}
121117
}
118+
119+
class TestConformanceWithoutStripping : InnerSendableTypes {
120+
// expected-error@-1 {{type 'TestConformanceWithoutStripping' does not conform to protocol 'InnerSendableTypes'}}
121+
122+
func test(_ options: [String: any Sendable]) {
123+
// expected-note@-1 {{candidate has non-matching type '([String : any Sendable]) -> ()'}}
124+
}
125+
126+
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) {
127+
// expected-note@-1 {{candidate has non-matching type '(String, @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) -> ()'}}
128+
}
129+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: %empty-directory(%t/sdk)
3+
// RUN: split-file %s %t/src
4+
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \
6+
// RUN: -import-objc-header %t/src/Test.h \
7+
// RUN: -swift-version 5 \
8+
// RUN: -strict-concurrency=complete \
9+
// RUN: -enable-experimental-feature SendableCompletionHandlers \
10+
// RUN: -module-name main -I %t -verify
11+
12+
// REQUIRES: objc_interop
13+
// REQUIRES: asserts
14+
15+
//--- Test.h
16+
#define SWIFT_SENDABLE __attribute__((__swift_attr__("@Sendable")))
17+
#define NONSENDABLE __attribute__((__swift_attr__("@_nonSendable")))
18+
#define MAIN_ACTOR __attribute__((__swift_attr__("@MainActor")))
19+
20+
#pragma clang assume_nonnull begin
21+
22+
@import Foundation;
23+
24+
@interface MyValue : NSObject
25+
@end
26+
27+
SWIFT_SENDABLE
28+
@protocol P <NSObject>
29+
@end
30+
31+
@interface SendableValue : NSObject<P>
32+
@end
33+
34+
SWIFT_SENDABLE
35+
@interface SendableMyValue : MyValue
36+
@end
37+
38+
typedef void (^CompletionHandler)(void (^ SWIFT_SENDABLE)(void)) SWIFT_SENDABLE;
39+
40+
@interface Test : NSObject
41+
-(void) makeRequest:
42+
(NSString *)typeIdentifier
43+
loadHandler:(void (^SWIFT_SENDABLE )(void (SWIFT_SENDABLE ^)(void)))loadHandler;
44+
-(void) withSendableId: (void (^)(SWIFT_SENDABLE id)) handler;
45+
-(void) withSendableCustom: (void (^)(MyValue *_Nullable SWIFT_SENDABLE)) handler;
46+
-(void) withNonSendable:(NSString *)operation completionHandler:(void (^ _Nullable NONSENDABLE)(NSString *_Nullable, NSError * _Nullable)) handler;
47+
-(void) withAliasCompletionHandler:(CompletionHandler)handler;
48+
@end
49+
50+
// Placement of SWIFT_SENDABLE matters here
51+
void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^block)(void));
52+
53+
@interface TestWithSendableID<T: SWIFT_SENDABLE id> : NSObject
54+
-(void) add: (T) object;
55+
@end
56+
57+
@interface TestWithSendableSuperclass<T: MyValue *SWIFT_SENDABLE> : NSObject
58+
-(void) add: (T) object;
59+
@end
60+
61+
@protocol InnerSendableTypes
62+
-(void) test:(NSDictionary<NSString *, SWIFT_SENDABLE id> *)options;
63+
-(void) testWithCallback:(NSString *)name handler:(MAIN_ACTOR void (^)(NSDictionary<NSString *, SWIFT_SENDABLE id> *, NSError * _Nullable))handler;
64+
@end
65+
66+
#pragma clang assume_nonnull end
67+
68+
//--- main.swift
69+
70+
func test_sendable_attr_in_type_context(test: Test) {
71+
let fn: (String?, (any Error)?) -> Void = { _,_ in }
72+
73+
test.withNonSendable("", completionHandler: fn) // Ok
74+
75+
test.makeRequest("id") {
76+
doSomethingConcurrently($0) // Ok
77+
}
78+
79+
test.makeRequest("id") { callback in
80+
_ = { @Sendable in
81+
callback() // Ok
82+
}
83+
}
84+
85+
test.withSendableId { id in
86+
_ = { @Sendable in
87+
print(id) // Ok
88+
}
89+
}
90+
91+
test.withSendableCustom { val in
92+
_ = { @Sendable in
93+
print(val!)
94+
}
95+
}
96+
97+
let _: (@escaping @Sendable (@escaping @Sendable () -> Void) -> Void) -> Void = test.withAliasCompletionHandler
98+
99+
test.withAliasCompletionHandler { callback in
100+
doSomethingConcurrently(callback) // Ok
101+
}
102+
103+
_ = TestWithSendableID<SendableValue>() // Ok
104+
105+
// TOOD(diagnostics): Duplicate diagnostics
106+
TestWithSendableID().add(MyValue())
107+
// expected-warning@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
108+
109+
TestWithSendableSuperclass().add(SendableMyValue()) // Ok
110+
111+
// TOOD(diagnostics): Duplicate diagnostics
112+
TestWithSendableSuperclass().add(MyValue())
113+
// expected-warning@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
114+
}
115+
116+
class TestConformanceWithStripping : InnerSendableTypes {
117+
// expected-error@-1 {{type 'TestConformanceWithStripping' does not conform to protocol 'InnerSendableTypes'}}
118+
119+
func test(_ options: [String: Any]) {
120+
// expected-note@-1 {{candidate has non-matching type '([String : Any]) -> ()'}}
121+
}
122+
123+
func test(withCallback name: String, handler: @escaping @MainActor ([String : Any], (any Error)?) -> Void) {
124+
// expected-note@-1 {{candidate has non-matching type '(String, @escaping @MainActor ([String : Any], (any Error)?) -> Void) -> ()'}}
125+
}
126+
}
127+
128+
class TestConformanceWithoutStripping : InnerSendableTypes {
129+
func test(_ options: [String: any Sendable]) { // Ok
130+
}
131+
132+
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) { // Ok
133+
}
134+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: %empty-directory(%t/sdk)
3+
// RUN: split-file %s %t/src
4+
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -typecheck %t/src/main.swift \
6+
// RUN: -import-objc-header %t/src/Test.h \
7+
// RUN: -swift-version 6 \
8+
// RUN: -enable-experimental-feature SendableCompletionHandlers \
9+
// RUN: -module-name main -I %t -verify
10+
11+
// REQUIRES: objc_interop
12+
// REQUIRES: asserts
13+
14+
//--- Test.h
15+
#define SWIFT_SENDABLE __attribute__((__swift_attr__("@Sendable")))
16+
#define NONSENDABLE __attribute__((__swift_attr__("@_nonSendable")))
17+
#define MAIN_ACTOR __attribute__((__swift_attr__("@MainActor")))
18+
19+
#pragma clang assume_nonnull begin
20+
21+
@import Foundation;
22+
23+
@interface MyValue : NSObject
24+
@end
25+
26+
SWIFT_SENDABLE
27+
@protocol P <NSObject>
28+
@end
29+
30+
@interface SendableValue : NSObject<P>
31+
@end
32+
33+
SWIFT_SENDABLE
34+
@interface SendableMyValue : MyValue
35+
@end
36+
37+
typedef void (^CompletionHandler)(void (^ SWIFT_SENDABLE)(void)) SWIFT_SENDABLE;
38+
39+
@interface Test : NSObject
40+
-(void) makeRequest:
41+
(NSString *)typeIdentifier
42+
loadHandler:(void (^SWIFT_SENDABLE )(void (SWIFT_SENDABLE ^)(void)))loadHandler;
43+
-(void) withSendableId: (void (^)(SWIFT_SENDABLE id)) handler;
44+
-(void) withSendableCustom: (void (^)(MyValue *_Nullable SWIFT_SENDABLE)) handler;
45+
-(void) withNonSendable:(NSString *)operation completionHandler:(void (^ _Nullable NONSENDABLE)(NSString *_Nullable, NSError * _Nullable)) handler;
46+
-(void) withAliasCompletionHandler:(CompletionHandler)handler;
47+
@end
48+
49+
// Placement of SWIFT_SENDABLE matters here
50+
void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^block)(void));
51+
52+
@interface TestWithSendableID<T: SWIFT_SENDABLE id> : NSObject
53+
-(void) add: (T) object;
54+
@end
55+
56+
@interface TestWithSendableSuperclass<T: MyValue *SWIFT_SENDABLE> : NSObject
57+
-(void) add: (T) object;
58+
@end
59+
60+
@protocol InnerSendableTypes
61+
-(void) test:(NSDictionary<NSString *, SWIFT_SENDABLE id> *)options;
62+
-(void) testWithCallback:(NSString *)name handler:(MAIN_ACTOR void (^)(NSDictionary<NSString *, SWIFT_SENDABLE id> *, NSError * _Nullable))handler;
63+
@end
64+
65+
#pragma clang assume_nonnull end
66+
67+
//--- main.swift
68+
69+
func test_sendable_attr_in_type_context(test: Test) {
70+
let fn: (String?, (any Error)?) -> Void = { _,_ in }
71+
72+
test.withNonSendable("", completionHandler: fn) // Ok
73+
74+
test.makeRequest("id") {
75+
doSomethingConcurrently($0) // Ok
76+
}
77+
78+
test.makeRequest("id") { callback in
79+
_ = { @Sendable in
80+
callback() // Ok
81+
}
82+
}
83+
84+
test.withSendableId { id in
85+
_ = { @Sendable in
86+
print(id) // Ok
87+
}
88+
}
89+
90+
test.withSendableCustom { val in
91+
_ = { @Sendable in
92+
print(val!)
93+
}
94+
}
95+
96+
let _: (@escaping @Sendable (@escaping @Sendable () -> Void) -> Void) -> Void = test.withAliasCompletionHandler
97+
98+
test.withAliasCompletionHandler { callback in
99+
doSomethingConcurrently(callback) // Ok
100+
}
101+
102+
_ = TestWithSendableID<SendableValue>() // Ok
103+
104+
// TOOD(diagnostics): Duplicate diagnostics
105+
TestWithSendableID().add(MyValue())
106+
// expected-error@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
107+
108+
TestWithSendableSuperclass().add(SendableMyValue()) // Ok
109+
110+
// TOOD(diagnostics): Duplicate diagnostics
111+
TestWithSendableSuperclass().add(MyValue())
112+
// expected-error@-1 3 {{type 'MyValue' does not conform to the 'Sendable' protocol}}
113+
}
114+
115+
class TestConformanceWithStripping : InnerSendableTypes {
116+
// expected-error@-1 {{type 'TestConformanceWithStripping' does not conform to protocol 'InnerSendableTypes'}}
117+
118+
func test(_ options: [String: Any]) {
119+
// expected-note@-1 {{candidate has non-matching type '([String : Any]) -> ()'}}
120+
}
121+
122+
func test(withCallback name: String, handler: @escaping @MainActor ([String : Any], (any Error)?) -> Void) {
123+
// expected-note@-1 {{candidate has non-matching type '(String, @escaping @MainActor ([String : Any], (any Error)?) -> Void) -> ()'}}
124+
}
125+
}
126+
127+
class TestConformanceWithoutStripping : InnerSendableTypes {
128+
func test(_ options: [String: any Sendable]) { // Ok
129+
}
130+
131+
func test(withCallback name: String, handler: @escaping @MainActor ([String : any Sendable], (any Error)?) -> Void) { // Ok
132+
}
133+
}

0 commit comments

Comments
 (0)