Skip to content

Commit cad921d

Browse files
authored
Merge pull request #19567 from benlangmuir/complete-unresolved-optional
[codecomplete] Fix unresolved member completion for T within Optional<T>
2 parents 9e0e552 + 4deb2d6 commit cad921d

File tree

2 files changed

+45
-24
lines changed

2 files changed

+45
-24
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3752,33 +3752,45 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
37523752
}
37533753
}
37543754

3755+
void getUnresolvedMemberCompletions(Type T) {
3756+
if (!T->getNominalOrBoundGenericNominal())
3757+
return;
3758+
3759+
// We can only say .foo where foo is a static member of the contextual
3760+
// type and has the same type (or if the member is a function, then the
3761+
// same result type) as the contextual type.
3762+
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) {
3763+
if (!VD->hasInterfaceType()) {
3764+
TypeResolver->resolveDeclSignature(VD);
3765+
if (!VD->hasInterfaceType())
3766+
return false;
3767+
}
3768+
3769+
auto declTy = VD->getInterfaceType();
3770+
while (auto FT = declTy->getAs<AnyFunctionType>())
3771+
declTy = FT->getResult();
3772+
return declTy->isEqual(T);
3773+
});
3774+
3775+
auto baseType = MetatypeType::get(T);
3776+
llvm::SaveAndRestore<LookupKind> SaveLook(Kind, LookupKind::ValueExpr);
3777+
llvm::SaveAndRestore<Type> SaveType(ExprType, baseType);
3778+
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
3779+
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
3780+
TypeResolver.get(),
3781+
/*includeInstanceMembers=*/false);
3782+
}
3783+
37553784
void getUnresolvedMemberCompletions(ArrayRef<Type> Types) {
37563785
NeedLeadingDot = !HaveDot;
37573786
for (auto T : Types) {
3758-
if (T && T->getNominalOrBoundGenericNominal()) {
3759-
// We can only say .foo where foo is a static member of the contextual
3760-
// type and has the same type (or if the member is a function, then the
3761-
// same result type) as the contextual type.
3762-
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) {
3763-
if (!VD->hasInterfaceType()) {
3764-
TypeResolver->resolveDeclSignature(VD);
3765-
if (!VD->hasInterfaceType())
3766-
return false;
3767-
}
3768-
3769-
auto declTy = VD->getInterfaceType();
3770-
while (auto FT = declTy->getAs<AnyFunctionType>())
3771-
declTy = FT->getResult();
3772-
return declTy->isEqual(T);
3773-
});
3774-
3775-
auto baseType = MetatypeType::get(T);
3776-
llvm::SaveAndRestore<LookupKind> SaveLook(Kind, LookupKind::ValueExpr);
3777-
llvm::SaveAndRestore<Type> SaveType(ExprType, baseType);
3778-
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
3779-
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
3780-
TypeResolver.get(),
3781-
/*includeInstanceMembers=*/false);
3787+
if (T) {
3788+
// FIXME: we should also include .some/.none from optional itself but
3789+
// getUnresolvedMemberCompletions doesn't ever return them since the
3790+
// interface type in the FilteredDeclConsumer will not match the bound
3791+
// generic type expected.
3792+
T = T->lookThroughAllOptionalTypes();
3793+
getUnresolvedMemberCompletions(T);
37823794
}
37833795
}
37843796
}

test/IDE/complete_unresolved_members.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_8 | %FileCheck %s -check-prefix=UNRESOLVED_3
1313
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_9 | %FileCheck %s -check-prefix=UNRESOLVED_3
14+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3
15+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3
1416

1517
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3
1618
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_13 | %FileCheck %s -check-prefix=UNRESOLVED_3
@@ -116,6 +118,7 @@ func OptionSetTaker6(_ Op1: SomeOptions2, _ Op2: SomeOptions1) {}
116118
func OptionSetTaker7(_ Op1: SomeOptions1, _ Op2: SomeOptions2) -> Int {return 0}
117119

118120
func EnumTaker1(_ E : SomeEnum1) {}
121+
func optionalEnumTaker1(_ : SomeEnum1?) {}
119122

120123
class OptionTakerContainer1 {
121124
func OptionSetTaker1(_ op : SomeOptions1) {}
@@ -179,6 +182,12 @@ class C4 {
179182
func f3() {
180183
OptionSetTaker5(.Option1, .Option4, .#^UNRESOLVED_12^#, .West)
181184
}
185+
func f4() {
186+
var _: SomeEnum1? = .#^UNRESOLVED_OPT_1^#
187+
}
188+
func f5() {
189+
optionalEnumTaker1(.#^UNRESOLVED_OPT_2^#)
190+
}
182191
}
183192
// UNRESOLVED_3: Begin completions
184193
// UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North

0 commit comments

Comments
 (0)