Skip to content

Commit da052e5

Browse files
committed
[TypeChecker] Allow @dynamicMemberLookup subscript index to compose key path with protocols
Allow to compose key path type with a protocol as a way to express additional requirements on the parameter. For example: ``` struct Test<R> { subscript<V>(dynamicMember member: KeyPath<R, V> & Sendable) -> V { ... } } ```
1 parent 7d32605 commit da052e5

File tree

3 files changed

+38
-0
lines changed

3 files changed

+38
-0
lines changed

lib/Sema/TypeCheckAttr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/AST/DiagnosticsParse.h"
2929
#include "swift/AST/DiagnosticsSema.h"
3030
#include "swift/AST/Effects.h"
31+
#include "swift/AST/ExistentialLayout.h"
3132
#include "swift/AST/GenericEnvironment.h"
3233
#include "swift/AST/ImportCache.h"
3334
#include "swift/AST/ModuleNameLookup.h"
@@ -1826,6 +1827,15 @@ bool swift::isValidKeyPathDynamicMemberLookup(SubscriptDecl *decl,
18261827
return false;
18271828

18281829
auto paramTy = decl->getIndices()->get(0)->getInterfaceType();
1830+
1831+
// Allow to compose key path type with a protocol as a way to express
1832+
// additional requirements on the parameter.
1833+
if (auto *existential = paramTy->getAs<ExistentialType>()) {
1834+
paramTy = existential->getExistentialLayout().explicitSuperclass;
1835+
if (!paramTy)
1836+
return false;
1837+
}
1838+
18291839
return paramTy->isKeyPath() ||
18301840
paramTy->isWritableKeyPath() ||
18311841
paramTy->isReferenceWritableKeyPath();

test/Concurrency/sendable_keypaths.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,3 +124,17 @@ do {
124124
// TODO: This should be diagnosed by the isolation checker because implicitly synthesized closures captures a non-Sendable value.
125125
testSendableFn(v: v, \.[42, CondSendable(nonSendable)])
126126
}
127+
128+
// @dynamicMemberLookup with Sendable requirement
129+
do {
130+
@dynamicMemberLookup
131+
struct Test<T> {
132+
var obj: T
133+
134+
subscript<U>(dynamicMember member: KeyPath<T, U> & Sendable) -> U {
135+
get { obj[keyPath: member] }
136+
}
137+
}
138+
139+
_ = Test(obj: "Hello").utf8.count // Ok
140+
}

test/Interpreter/keypath.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,17 @@ do {
134134
// CHECK: 42
135135
test(v: S(i: 42), \.i)
136136
}
137+
138+
do {
139+
@dynamicMemberLookup
140+
struct Test<T> {
141+
var obj: T
142+
143+
subscript<U>(dynamicMember member: KeyPath<T, U> & Sendable) -> U {
144+
get { obj[keyPath: member] }
145+
}
146+
}
147+
148+
// CHECK: 5
149+
print(Test(obj: "Hello").utf8.count)
150+
}

0 commit comments

Comments
 (0)