Skip to content

Commit 636d63e

Browse files
committed
[code-completion] Handle nested keypath dynamic lookup correctly
If the root type of the KeyPath also has dynamic member lookup, we need to look through it. rdar://problem/50450037
1 parent 77a411a commit 636d63e

File tree

2 files changed

+50
-21
lines changed

2 files changed

+50
-21
lines changed

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -864,27 +864,35 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
864864

865865
struct KeyPathDynamicMemberConsumer : public VisibleDeclConsumer {
866866
VisibleDeclConsumer &consumer;
867-
std::function<bool(DeclBaseName)> seenBaseName;
867+
std::function<bool(DeclBaseName)> seenStaticBaseName;
868+
llvm::DenseSet<DeclBaseName> seen;
868869

869870
SubscriptDecl *currentSubscript = nullptr;
870871
Type currentBaseType = Type();
871872

872873
KeyPathDynamicMemberConsumer(VisibleDeclConsumer &consumer,
873874
std::function<bool(DeclBaseName)> seenBaseName)
874-
: consumer(consumer), seenBaseName(std::move(seenBaseName)) {}
875+
: consumer(consumer), seenStaticBaseName(std::move(seenBaseName)) {}
876+
877+
bool checkShadowed(ValueDecl *VD) {
878+
// Dynamic lookup members are only visible if they are not shadowed by
879+
// other members.
880+
return !isa<SubscriptDecl>(VD) && seen.insert(VD->getBaseName()).second &&
881+
!seenStaticBaseName(VD->getBaseName());
882+
}
875883

876884
void foundDecl(ValueDecl *VD, DeclVisibilityKind reason,
877885
DynamicLookupInfo dynamicLookupInfo) override {
886+
assert(dynamicLookupInfo.getKind() !=
887+
DynamicLookupInfo::KeyPathDynamicMember);
888+
878889
// Only variables and subscripts are allowed in a keypath.
879890
if (!isa<AbstractStorageDecl>(VD))
880891
return;
881892

882-
assert(dynamicLookupInfo.getKind() !=
883-
DynamicLookupInfo::KeyPathDynamicMember);
884-
885893
// Dynamic lookup members are only visible if they are not shadowed by
886894
// non-dynamic members.
887-
if (isa<SubscriptDecl>(VD) || !seenBaseName(VD->getBaseName()))
895+
if (checkShadowed(VD))
888896
consumer.foundDecl(VD, DeclVisibilityKind::DynamicLookup,
889897
{currentSubscript, currentBaseType, reason});
890898
}
@@ -913,7 +921,28 @@ static void lookupVisibleDynamicMemberLookupDecls(
913921
Type baseType, KeyPathDynamicMemberConsumer &consumer,
914922
const DeclContext *dc, LookupState LS, DeclVisibilityKind reason,
915923
LazyResolver *typeResolver, GenericSignatureBuilder *GSB,
916-
VisitedSet &visited) {
924+
VisitedSet &visited, llvm::DenseSet<TypeBase *> &seenDynamicLookup);
925+
926+
static void lookupVisibleMemberAndDynamicMemberDecls(
927+
Type baseType, VisibleDeclConsumer &consumer,
928+
KeyPathDynamicMemberConsumer &dynamicMemberConsumer, const DeclContext *DC,
929+
LookupState LS, DeclVisibilityKind reason, LazyResolver *typeResolver,
930+
GenericSignatureBuilder *GSB, VisitedSet &visited,
931+
llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
932+
lookupVisibleMemberDeclsImpl(baseType, consumer, DC, LS, reason, typeResolver,
933+
GSB, visited);
934+
lookupVisibleDynamicMemberLookupDecls(baseType, dynamicMemberConsumer, DC, LS,
935+
reason, typeResolver, GSB, visited,
936+
seenDynamicLookup);
937+
}
938+
939+
static void lookupVisibleDynamicMemberLookupDecls(
940+
Type baseType, KeyPathDynamicMemberConsumer &consumer,
941+
const DeclContext *dc, LookupState LS, DeclVisibilityKind reason,
942+
LazyResolver *typeResolver, GenericSignatureBuilder *GSB,
943+
VisitedSet &visited, llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
944+
if (!seenDynamicLookup.insert(baseType.getPointer()).second)
945+
return;
917946

918947
if (!hasDynamicMemberLookupAttribute(baseType))
919948
return;
@@ -946,8 +975,9 @@ static void lookupVisibleDynamicMemberLookupDecls(
946975
KeyPathDynamicMemberConsumer::SubscriptChange(consumer, subscript,
947976
baseType);
948977

949-
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
950-
typeResolver, GSB, visited);
978+
lookupVisibleMemberAndDynamicMemberDecls(memberType, consumer, consumer, dc,
979+
LS, reason, typeResolver, GSB,
980+
visited, seenDynamicLookup);
951981
}
952982
}
953983

@@ -963,15 +993,14 @@ static void lookupVisibleMemberDecls(
963993
GenericSignatureBuilder *GSB) {
964994
OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC, TypeResolver);
965995
KeyPathDynamicMemberConsumer dynamicConsumer(
966-
overrideConsumer,
996+
Consumer,
967997
[&](DeclBaseName name) { return overrideConsumer.seenBaseName(name); });
968998

969999
VisitedSet Visited;
970-
lookupVisibleMemberDeclsImpl(BaseTy, overrideConsumer, CurrDC, LS, Reason,
971-
TypeResolver, GSB, Visited);
972-
973-
lookupVisibleDynamicMemberLookupDecls(BaseTy, dynamicConsumer, CurrDC, LS,
974-
Reason, TypeResolver, GSB, Visited);
1000+
llvm::DenseSet<TypeBase *> seenDynamicLookup;
1001+
lookupVisibleMemberAndDynamicMemberDecls(
1002+
BaseTy, overrideConsumer, dynamicConsumer, CurrDC, LS, Reason,
1003+
TypeResolver, GSB, Visited, seenDynamicLookup);
9751004

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

test/IDE/complete_keypath_member_lookup.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ func testShadow1(r: Shadow1<Point>) {
142142
r.#^testShadow1^#
143143
}
144144
// testShadow1-NOT: x[#Int#];
145-
// testShadow1: Decl[InstanceVar]/CurrNominal: x[#String#];
146-
// testShadow1-NOT: x[#Int#];
147145
// testShadow1: Decl[InstanceVar]/CurrNominal: y[#Int#];
146+
// testShadow1-NOT: x[#Int#];
147+
// testShadow1: Decl[InstanceVar]/CurrNominal: x[#String#];
148148

149149
@dynamicMemberLookup
150150
protocol P {
@@ -312,16 +312,16 @@ func testAnyObjectRoot1(r: AnyObjectRoot) {
312312
func testNested1(r: Lens<Lens<Point>>) {
313313
r.#^testNested1^#
314314
// testNested1: Begin completions
315-
// FIXME-DAG: Decl[InstanceVar]/CurrNominal: x[#Int#];
316-
// FIXME-DAG: Decl[InstanceVar]/CurrNominal: y[#Int#];
315+
// testNested1-DAG: Decl[InstanceVar]/CurrNominal: x[#Int#];
316+
// testNested1-DAG: Decl[InstanceVar]/CurrNominal: y[#Int#];
317317
// testNested1: End completions
318318
}
319319

320320
func testNested2(r: Lens<Lens<Lens<Point>>>) {
321321
r.#^testNested2^#
322322
// testNested2: Begin completions
323-
// FIXME-DAG: Decl[InstanceVar]/CurrNominal: x[#Int#];
324-
// FIXME-DAG: Decl[InstanceVar]/CurrNominal: y[#Int#];
323+
// testNested2-DAG: Decl[InstanceVar]/CurrNominal: x[#Int#];
324+
// testNested2-DAG: Decl[InstanceVar]/CurrNominal: y[#Int#];
325325
// testNested2: End completions
326326
}
327327

0 commit comments

Comments
 (0)