Skip to content

Commit 2a80e98

Browse files
committed
[Sema] Allow associated type inference to skip @Sendable on ObjC witnesses
Witness checking itself is allowed to skip `@Sendable` mismatch in this situation. This is a narrow fix for `SendableCompletionHandlers` feature to make sure that the behavior doesn't change for non-ObjC witnesses
1 parent ffbbfb7 commit 2a80e98

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed

lib/Sema/AssociatedTypeInference.cpp

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2269,6 +2269,61 @@ AssociatedTypeInference::getPotentialTypeWitnessesByMatchingTypes(ValueDecl *req
22692269
return true;
22702270
}
22712271

2272+
bool mismatch(AnyFunctionType *firstType, AnyFunctionType *secondType,
2273+
Type sugaredFirstType) {
2274+
// Mismatch on sendability could be okay if everything else matches.
2275+
if (firstType->isSendable() != secondType->isSendable()) {
2276+
auto firstExtInfo = firstType->getExtInfo();
2277+
auto secondExtInfo = secondType->getExtInfo();
2278+
2279+
// If the requirement is Sendable, it's always okay because
2280+
// having witnesses differ only on `@Sendable` is already
2281+
// ambiguous, for example:
2282+
//
2283+
// protocol P {
2284+
// associatedtype T
2285+
// func test(_: @Sendable (T) -> Void)
2286+
// }
2287+
//
2288+
// struct S : P {
2289+
// func test(_: @Sendable (String) -> Void) {}
2290+
// func test(_: (Int) -> Void) {}
2291+
// }
2292+
//
2293+
// `T` is ambiguous and inferred as both `Int` and `String`.
2294+
if (firstType->isSendable()) {
2295+
return match(
2296+
firstType->withExtInfo(secondExtInfo.withSendable(false)),
2297+
secondType);
2298+
}
2299+
2300+
// If it's a witness that is Sendable but requirement isn't
2301+
// let's only allow matches if the witness comes from ObjC
2302+
// as a very narrow fix to avoid introducing new ambiguities
2303+
// like this:
2304+
//
2305+
// protocol P {
2306+
// associatedtype T
2307+
// func test(_: (T) -> Void)
2308+
// }
2309+
//
2310+
// struct S : P {
2311+
// func test(_: @Sendable (Int) -> Void) {}
2312+
// func test(_: (Int) -> Void) {}
2313+
// }
2314+
//
2315+
// Currently, there is only one binding for `T` - `Int`.
2316+
if (auto *witness = Inferred.Witness) {
2317+
if (witness->hasClangNode()) {
2318+
return match(firstType, secondType->withExtInfo(
2319+
firstExtInfo.withSendable(false)));
2320+
}
2321+
}
2322+
}
2323+
2324+
return false;
2325+
}
2326+
22722327
bool mismatch(GenericTypeParamType *selfParamType,
22732328
TypeBase *secondType, Type sugaredFirstType) {
22742329
if (selfParamType->isEqual(Conformance->getProtocol()->getSelfInterfaceType())) {

test/Concurrency/sendable_objc_attr_in_type_context_swift5.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
7878
-(void)willSendDataWithCompletion: (void (^)(void)) completion;
7979
@end
8080

81+
@interface DataHandler : NSObject
82+
+(void)sendDataWithCompletion: (void (^)(MyValue *)) completion;
83+
@end
84+
8185
#pragma clang assume_nonnull end
8286

8387
//--- main.swift
@@ -189,3 +193,13 @@ class ImplicitShadowing : NSObject, TestWitnesses {
189193
(self as AnyObject).willSendData { } // Ok
190194
}
191195
}
196+
197+
protocol CompletionWithoutSendable {
198+
associatedtype T
199+
static func sendData(completion: @escaping (T) -> Void) // expected-note {{expected sendability to match requirement here}}
200+
}
201+
202+
extension DataHandler : CompletionWithoutSendable {
203+
// expected-warning@-1 {{sendability of function types in class method 'sendData(completion:)' does not match requirement in protocol 'CompletionWithoutSendable'}}
204+
// It should be possible to infer `T` from method that mismatches on @Sendable in Swift 5 mode
205+
}

test/Concurrency/sendable_objc_attr_in_type_context_swift6.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ void doSomethingConcurrently(__attribute__((noescape)) void SWIFT_SENDABLE (^blo
7878
-(void)willSendDataWithCompletion: (void (^)(void)) completion;
7979
@end
8080

81+
@interface DataHandler : NSObject
82+
+(void)sendDataWithCompletion: (void (^)(MyValue *)) completion;
83+
@end
84+
8185
#pragma clang assume_nonnull end
8286

8387
//--- main.swift
@@ -196,3 +200,13 @@ class ImplicitShadowing : NSObject, TestWitnesses {
196200
(self as AnyObject).willSendData { } // Ok
197201
}
198202
}
203+
204+
protocol CompletionWithoutSendable {
205+
associatedtype T
206+
static func sendData(completion: @escaping (T) -> Void) // expected-note {{expected sendability to match requirement here}}
207+
}
208+
209+
extension DataHandler : CompletionWithoutSendable {
210+
// expected-error@-1 {{sendability of function types in class method 'sendData(completion:)' does not match requirement in protocol 'CompletionWithoutSendable'}}
211+
// It should be possible to infer `T` from method that mismatches on @Sendable in Swift 5 mode
212+
}

0 commit comments

Comments
 (0)