Skip to content

Commit 436a279

Browse files
authored
Merge pull request #83348 from xedin/rdar-138227393
[CSApply] Key path dynamic member lookup argument is Sendable only if its captures are
2 parents 72299f6 + db13a63 commit 436a279

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

lib/Sema/CSApply.cpp

Lines changed: 27 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->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));
@@ -3687,6 +3708,8 @@ namespace {
36873708
if (!argExpr)
36883709
return nullptr;
36893710

3711+
solution.recordSingleArgMatchingChoice(cs.getConstraintLocator(expr));
3712+
36903713
// Build an argument list.
36913714
auto *argList =
36923715
ArgumentList::forImplicitSingle(ctx, ctx.Id_dynamicMember, argExpr);

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)