Skip to content

Commit 9c9e408

Browse files
committed
[code-completion] Avoid name copy for non dynamic member types
Per review feedback. Also add some test cases that should fail dynamic member lookup.
1 parent 5076001 commit 9c9e408

File tree

2 files changed

+64
-12
lines changed

2 files changed

+64
-12
lines changed

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -628,9 +628,7 @@ static void lookupVisibleDynamicMemberLookupDecls(
628628
LookupState LS, DeclVisibilityKind reason, LazyResolver *typeResolver,
629629
GenericSignatureBuilder *GSB, VisitedSet &visited) {
630630

631-
if (!hasDynamicMemberLookupAttribute(baseType))
632-
return;
633-
631+
assert(hasDynamicMemberLookupAttribute(baseType));
634632
auto &ctx = dc->getASTContext();
635633

636634
// Lookup the `subscript(dynamicMember:)` methods in this type.
@@ -652,9 +650,12 @@ static void lookupVisibleDynamicMemberLookupDecls(
652650

653651
auto subs =
654652
baseType->getMemberSubstitutionMap(dc->getParentModule(), subscript);
655-
if (auto memberType = rootType->subst(subs))
656-
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
657-
typeResolver, GSB, visited);
653+
auto memberType = rootType->subst(subs);
654+
if (!memberType || !memberType->mayHaveMembers())
655+
continue;
656+
657+
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
658+
typeResolver, GSB, visited);
658659
}
659660
}
660661

@@ -888,13 +889,15 @@ static void lookupVisibleMemberDecls(
888889
lookupVisibleMemberDeclsImpl(BaseTy, overrideConsumer, CurrDC, LS, Reason,
889890
TypeResolver, GSB, Visited);
890891

891-
llvm::DenseSet<DeclBaseName> knownMembers;
892-
for (auto &kv : overrideConsumer.FoundDecls) {
893-
knownMembers.insert(kv.first);
892+
if (hasDynamicMemberLookupAttribute(BaseTy)) {
893+
llvm::DenseSet<DeclBaseName> knownMembers;
894+
for (auto &kv : overrideConsumer.FoundDecls) {
895+
knownMembers.insert(kv.first);
896+
}
897+
ShadowedKeyPathMembers dynamicConsumer(overrideConsumer, knownMembers);
898+
lookupVisibleDynamicMemberLookupDecls(BaseTy, dynamicConsumer, CurrDC, LS,
899+
Reason, TypeResolver, GSB, Visited);
894900
}
895-
ShadowedKeyPathMembers dynamicConsumer(overrideConsumer, knownMembers);
896-
lookupVisibleDynamicMemberLookupDecls(BaseTy, dynamicConsumer, CurrDC, LS,
897-
Reason, TypeResolver, GSB, Visited);
898901

899902
// Report the declarations we found to the real consumer.
900903
for (const auto &DeclAndReason : overrideConsumer.DeclsToReport)

test/IDE/complete_keypath_member_lookup.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testProtocolConform1 | %FileCheck %s -check-prefix=testProtocolConform1
1313
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OnSelf1 | %FileCheck %s -check-prefix=OnSelf1
1414
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testSelfExtension1 | %FileCheck %s -check-prefix=testSelfExtension1
15+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testInvalid1 | %FileCheck %s -check-prefix=testInvalid1
16+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testInvalid2 | %FileCheck %s -check-prefix=testInvalid2
17+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testInvalid3 | %FileCheck %s -check-prefix=testInvalid3
18+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=testInvalid4 | %FileCheck %s -check-prefix=testInvalid4
1519

1620
struct Point {
1721
var x: Int
@@ -219,3 +223,48 @@ extension Lens where T: HalfRect {
219223
// testSelfExtension1-NOT: bottomRight
220224
// testSelfExtension1: Decl[InstanceVar]/CurrNominal: topLeft[#Point#];
221225
// testSelfExtension1-NOT: bottomRight
226+
227+
struct Invalid1 {
228+
subscript<U>(dynamicMember member: KeyPath<Rectangle, U>) -> U {
229+
return Point(x: 0, y: 1)[keyPath: member]
230+
}
231+
}
232+
func testInvalid1(r: Invalid1) {
233+
r.#^testInvalid1^#
234+
}
235+
// testInvalid1-NOT: topLeft
236+
237+
@dynamicMemberLookup
238+
struct Invalid2 {
239+
subscript<U>(dynamicMember: KeyPath<Rectangle, U>) -> U {
240+
return Point(x: 0, y: 1)[keyPath: dynamicMember]
241+
}
242+
}
243+
func testInvalid2(r: Invalid2) {
244+
r.#^testInvalid2^#
245+
}
246+
// testInvalid2-NOT: topLeft
247+
248+
@dynamicMemberLookup
249+
struct Invalid3 {
250+
subscript<U>(dynamicMember member: Rectangle) -> U {
251+
return Point(x: 0, y: 1)[keyPath: member]
252+
}
253+
}
254+
func testInvalid3(r: Invalid3) {
255+
r.#^testInvalid3^#
256+
}
257+
// testInvalid3-NOT: topLeft
258+
259+
struct NotKeyPath<T, U> {}
260+
261+
@dynamicMemberLookup
262+
struct Invalid4 {
263+
subscript<U>(dynamicMember member: NotKeyPath<Rectangle, U>) -> U {
264+
return Point(x: 0, y: 1)[keyPath: member]
265+
}
266+
}
267+
func testInvalid4(r: Invalid4) {
268+
r.#^testInvalid4^#
269+
}
270+
// testInvalid4-NOT: topLeft

0 commit comments

Comments
 (0)