Skip to content

Commit ae4827a

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 40df0c4 commit ae4827a

File tree

2 files changed

+64
-12
lines changed

2 files changed

+64
-12
lines changed

lib/Sema/LookupVisibleDecls.cpp

+15-12
Original file line numberDiff line numberDiff line change
@@ -626,9 +626,7 @@ static void lookupVisibleDynamicMemberLookupDecls(
626626
LookupState LS, DeclVisibilityKind reason, LazyResolver *typeResolver,
627627
GenericSignatureBuilder *GSB, VisitedSet &visited) {
628628

629-
if (!hasDynamicMemberLookupAttribute(baseType))
630-
return;
631-
629+
assert(hasDynamicMemberLookupAttribute(baseType));
632630
auto &ctx = dc->getASTContext();
633631

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

651649
auto subs =
652650
baseType->getMemberSubstitutionMap(dc->getParentModule(), subscript);
653-
if (auto memberType = rootType->subst(subs))
654-
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
655-
typeResolver, GSB, visited);
651+
auto memberType = rootType->subst(subs);
652+
if (!memberType || !memberType->mayHaveMembers())
653+
continue;
654+
655+
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
656+
typeResolver, GSB, visited);
656657
}
657658
}
658659

@@ -886,13 +887,15 @@ static void lookupVisibleMemberDecls(
886887
lookupVisibleMemberDeclsImpl(BaseTy, overrideConsumer, CurrDC, LS, Reason,
887888
TypeResolver, GSB, Visited);
888889

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

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

test/IDE/complete_keypath_member_lookup.swift

+49
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)