Skip to content

Commit 045909b

Browse files
committed
[CSApply] Key path dynamic member lookup argument is Sendable only if its captures are
Previously dynamic member subscript wasn't allowed to use `& Sendable`, since this restriction was lifted the argument cannot simply assume the parameter type any longer, the key path captures have to be checked to determine whether it could be marked as Sendable or not. Resolves: #77105 Resolves: rdar://138227393
1 parent 56976c5 commit 045909b

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

lib/Sema/CSApply.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2556,18 +2556,39 @@ namespace {
25562556
/// Build an implicit argument for keypath based dynamic lookup,
25572557
/// which consists of KeyPath expression and a single component.
25582558
///
2559-
/// \param argType The type of the keypath subscript argument.
2559+
/// \param paramType The type of the keypath subscript parameter
2560+
/// this argument is passed to.
25602561
/// \param dotLoc The location of the '.' preceding member name.
25612562
/// \param memberLoc The locator to be associated with new argument.
2562-
Expr *buildKeyPathDynamicMemberArgExpr(Type argType, SourceLoc dotLoc,
2563+
Expr *buildKeyPathDynamicMemberArgExpr(Type paramType, SourceLoc dotLoc,
25632564
ConstraintLocator *memberLoc) {
25642565
using Component = KeyPathExpr::Component;
25652566
auto *anchor = getAsExpr(memberLoc->getAnchor());
25662567

25672568
auto makeKeyPath = [&](ArrayRef<Component> components) -> Expr * {
2569+
Type keyPathTy = paramType;
2570+
2571+
// If parameter of a dynamic member lookup is `& Sendable` type
2572+
// we need to check key path captures to determine whether the
2573+
// argument could be `& Sendable` as well or not.
2574+
if (paramType->isExistentialType() && paramType->isSendableType()) {
2575+
auto allCapturesAreSendable = [&](const Component &component) {
2576+
auto *argList = component.getArgs();
2577+
if (!argList)
2578+
return true;
2579+
2580+
return llvm::all_of(*argList, [&](const auto &arg) {
2581+
return solution.getResolvedType(arg.getExpr())->isSendableType();
2582+
});
2583+
};
2584+
2585+
if (!llvm::all_of(components, allCapturesAreSendable))
2586+
keyPathTy = paramType->castTo<ExistentialType>()->getSuperclass();
2587+
}
2588+
25682589
auto *kp = KeyPathExpr::createImplicit(ctx, /*backslashLoc*/ dotLoc,
25692590
components, anchor->getEndLoc());
2570-
kp->setType(argType);
2591+
kp->setType(keyPathTy);
25712592
cs.cacheExprTypes(kp);
25722593

25732594
// See whether there's an equivalent ObjC key path string we can produce
@@ -2576,7 +2597,7 @@ namespace {
25762597
return kp;
25772598
};
25782599

2579-
Type keyPathTy = argType;
2600+
Type keyPathTy = paramType;
25802601
if (auto *existential = keyPathTy->getAs<ExistentialType>()) {
25812602
keyPathTy = existential->getSuperclass();
25822603
assert(isKnownKeyPathType(keyPathTy));

test/Concurrency/sendable_keypaths.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,3 +258,22 @@ do {
258258
// TODO(rdar://125948508): This shouldn't be ambiguous (@Sendable version should be preferred)
259259
let _: () -> Void = forward(Test.fn) // expected-error {{conflicting arguments to generic parameter 'T' ('@Sendable () -> ()' vs. '() -> Void')}}
260260
}
261+
262+
// https://github.com/swiftlang/swift/issues/77105
263+
do {
264+
@dynamicMemberLookup
265+
struct S<T> {
266+
subscript<U>(dynamicMember keyPath: KeyPath<T, U> & Sendable) -> U {
267+
fatalError()
268+
}
269+
}
270+
271+
struct Foo {
272+
subscript<T>(bar bar: T) -> Int { 42 }
273+
}
274+
275+
func test(s: S<Foo>) {
276+
_ = s[bar: NonSendable()]
277+
// expected-warning@-1 {{type 'KeyPath<Foo, Int>' does not conform to the 'Sendable' protocol; this is an error in the Swift 6 language mode}}
278+
}
279+
}

0 commit comments

Comments
 (0)