mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
[codecomplete] Fix unresolved member completion for T within Optional<T>
We need to look through the optional and find the members of T when doing completion in Optional<T>. let x: Foo? = .foo We still don't correctly complete .some/.none, which requires reconciling the unbound generic type we get from the decl with the real bound generic type. rdar://44767478
This commit is contained in:
@@ -3752,33 +3752,45 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void getUnresolvedMemberCompletions(Type T) {
|
||||
if (!T->getNominalOrBoundGenericNominal())
|
||||
return;
|
||||
|
||||
// We can only say .foo where foo is a static member of the contextual
|
||||
// type and has the same type (or if the member is a function, then the
|
||||
// same result type) as the contextual type.
|
||||
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) {
|
||||
if (!VD->hasInterfaceType()) {
|
||||
TypeResolver->resolveDeclSignature(VD);
|
||||
if (!VD->hasInterfaceType())
|
||||
return false;
|
||||
}
|
||||
|
||||
auto declTy = VD->getInterfaceType();
|
||||
while (auto FT = declTy->getAs<AnyFunctionType>())
|
||||
declTy = FT->getResult();
|
||||
return declTy->isEqual(T);
|
||||
});
|
||||
|
||||
auto baseType = MetatypeType::get(T);
|
||||
llvm::SaveAndRestore<LookupKind> SaveLook(Kind, LookupKind::ValueExpr);
|
||||
llvm::SaveAndRestore<Type> SaveType(ExprType, baseType);
|
||||
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
|
||||
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
|
||||
TypeResolver.get(),
|
||||
/*includeInstanceMembers=*/false);
|
||||
}
|
||||
|
||||
void getUnresolvedMemberCompletions(ArrayRef<Type> Types) {
|
||||
NeedLeadingDot = !HaveDot;
|
||||
for (auto T : Types) {
|
||||
if (T && T->getNominalOrBoundGenericNominal()) {
|
||||
// We can only say .foo where foo is a static member of the contextual
|
||||
// type and has the same type (or if the member is a function, then the
|
||||
// same result type) as the contextual type.
|
||||
FilteredDeclConsumer consumer(*this, [=](ValueDecl *VD, DeclVisibilityKind reason) {
|
||||
if (!VD->hasInterfaceType()) {
|
||||
TypeResolver->resolveDeclSignature(VD);
|
||||
if (!VD->hasInterfaceType())
|
||||
return false;
|
||||
}
|
||||
|
||||
auto declTy = VD->getInterfaceType();
|
||||
while (auto FT = declTy->getAs<AnyFunctionType>())
|
||||
declTy = FT->getResult();
|
||||
return declTy->isEqual(T);
|
||||
});
|
||||
|
||||
auto baseType = MetatypeType::get(T);
|
||||
llvm::SaveAndRestore<LookupKind> SaveLook(Kind, LookupKind::ValueExpr);
|
||||
llvm::SaveAndRestore<Type> SaveType(ExprType, baseType);
|
||||
llvm::SaveAndRestore<bool> SaveUnresolved(IsUnresolvedMember, true);
|
||||
lookupVisibleMemberDecls(consumer, baseType, CurrDeclContext,
|
||||
TypeResolver.get(),
|
||||
/*includeInstanceMembers=*/false);
|
||||
if (T) {
|
||||
// FIXME: we should also include .some/.none from optional itself but
|
||||
// getUnresolvedMemberCompletions doesn't ever return them since the
|
||||
// interface type in the FilteredDeclConsumer will not match the bound
|
||||
// generic type expected.
|
||||
T = T->lookThroughAllOptionalTypes();
|
||||
getUnresolvedMemberCompletions(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_8 | %FileCheck %s -check-prefix=UNRESOLVED_3
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_9 | %FileCheck %s -check-prefix=UNRESOLVED_3
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_1 | %FileCheck %s -check-prefix=UNRESOLVED_3
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_OPT_2 | %FileCheck %s -check-prefix=UNRESOLVED_3
|
||||
|
||||
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=UNRESOLVED_12 | %FileCheck %s -check-prefix=UNRESOLVED_3
|
||||
// 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) {}
|
||||
func OptionSetTaker7(_ Op1: SomeOptions1, _ Op2: SomeOptions2) -> Int {return 0}
|
||||
|
||||
func EnumTaker1(_ E : SomeEnum1) {}
|
||||
func optionalEnumTaker1(_ : SomeEnum1?) {}
|
||||
|
||||
class OptionTakerContainer1 {
|
||||
func OptionSetTaker1(_ op : SomeOptions1) {}
|
||||
@@ -179,6 +182,12 @@ class C4 {
|
||||
func f3() {
|
||||
OptionSetTaker5(.Option1, .Option4, .#^UNRESOLVED_12^#, .West)
|
||||
}
|
||||
func f4() {
|
||||
var _: SomeEnum1? = .#^UNRESOLVED_OPT_1^#
|
||||
}
|
||||
func f5() {
|
||||
optionalEnumTaker1(.#^UNRESOLVED_OPT_2^#)
|
||||
}
|
||||
}
|
||||
// UNRESOLVED_3: Begin completions
|
||||
// UNRESOLVED_3-DAG: Decl[EnumElement]/ExprSpecific: North[#SomeEnum1#]; name=North
|
||||
|
||||
Reference in New Issue
Block a user