Skip to content

Commit f56ada9

Browse files
authored
Merge pull request #24779 from benlangmuir/cc-nested-keypath-51
[5.1] [code-completion] Handle nested keypath dynamic lookup correctly
2 parents c9c68d6 + 7a732ef commit f56ada9

File tree

2 files changed

+61
-21
lines changed

2 files changed

+61
-21
lines changed

lib/Sema/LookupVisibleDecls.cpp

Lines changed: 55 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,39 @@ 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+
/// Enumerates all members of \c baseType, including both directly visible and
927+
/// members visible by keypath dynamic member lookup.
928+
///
929+
/// \note This is an implementation detail of \c lookupVisibleMemberDecls and
930+
/// exists to create the correct recursion for dynamic member lookup.
931+
static void lookupVisibleMemberAndDynamicMemberDecls(
932+
Type baseType, VisibleDeclConsumer &consumer,
933+
KeyPathDynamicMemberConsumer &dynamicMemberConsumer, const DeclContext *DC,
934+
LookupState LS, DeclVisibilityKind reason, LazyResolver *typeResolver,
935+
GenericSignatureBuilder *GSB, VisitedSet &visited,
936+
llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
937+
lookupVisibleMemberDeclsImpl(baseType, consumer, DC, LS, reason, typeResolver,
938+
GSB, visited);
939+
lookupVisibleDynamicMemberLookupDecls(baseType, dynamicMemberConsumer, DC, LS,
940+
reason, typeResolver, GSB, visited,
941+
seenDynamicLookup);
942+
}
943+
944+
/// Enumerates all keypath dynamic members of \c baseType, as seen from the
945+
/// context \c dc.
946+
///
947+
/// If \c baseType is \c @dynamicMemberLookup, this looks up any keypath
948+
/// dynamic member subscripts and looks up the members of the keypath's root
949+
/// type.
950+
static void lookupVisibleDynamicMemberLookupDecls(
951+
Type baseType, KeyPathDynamicMemberConsumer &consumer,
952+
const DeclContext *dc, LookupState LS, DeclVisibilityKind reason,
953+
LazyResolver *typeResolver, GenericSignatureBuilder *GSB,
954+
VisitedSet &visited, llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
955+
if (!seenDynamicLookup.insert(baseType.getPointer()).second)
956+
return;
917957

918958
if (!hasDynamicMemberLookupAttribute(baseType))
919959
return;
@@ -946,8 +986,9 @@ static void lookupVisibleDynamicMemberLookupDecls(
946986
KeyPathDynamicMemberConsumer::SubscriptChange(consumer, subscript,
947987
baseType);
948988

949-
lookupVisibleMemberDeclsImpl(memberType, consumer, dc, LS, reason,
950-
typeResolver, GSB, visited);
989+
lookupVisibleMemberAndDynamicMemberDecls(memberType, consumer, consumer, dc,
990+
LS, reason, typeResolver, GSB,
991+
visited, seenDynamicLookup);
951992
}
952993
}
953994

@@ -963,15 +1004,14 @@ static void lookupVisibleMemberDecls(
9631004
GenericSignatureBuilder *GSB) {
9641005
OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC, TypeResolver);
9651006
KeyPathDynamicMemberConsumer dynamicConsumer(
966-
overrideConsumer,
1007+
Consumer,
9671008
[&](DeclBaseName name) { return overrideConsumer.seenBaseName(name); });
9681009

9691010
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);
1011+
llvm::DenseSet<TypeBase *> seenDynamicLookup;
1012+
lookupVisibleMemberAndDynamicMemberDecls(
1013+
BaseTy, overrideConsumer, dynamicConsumer, CurrDC, LS, Reason,
1014+
TypeResolver, GSB, Visited, seenDynamicLookup);
9751015

9761016
// Report the declarations we found to the real consumer.
9771017
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)