Skip to content

[CodeCompletion] Don't take opaque types subst map into account #65170

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions include/swift/IDE/CompletionLookup.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,13 +461,17 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
DynamicLookupInfo dynamicLookupInfo);

private:
/// Normalize the type for 'isDupelicate' check.
Type normalizeTypeForDuplicationCheck(Type Ty);

/// Returns true if duplicate checking is enabled (via
/// \c shouldCheckForDuplicates) and this decl + type combination has been
/// checked previously. Returns false otherwise.
bool isDuplicate(const ValueDecl *D, Type Ty) {
if (!CheckForDuplicates)
return false;
return !PreviouslySeen.insert({D, Ty}).second;
return !PreviouslySeen.insert({D, normalizeTypeForDuplicationCheck(Ty)})
.second;
}

/// Returns true if duplicate checking is enabled (via
Expand All @@ -477,7 +481,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
if (!CheckForDuplicates)
return false;
Type Ty = getTypeOfMember(D, dynamicLookupInfo);
return !PreviouslySeen.insert({D, Ty}).second;
return !PreviouslySeen.insert({D, normalizeTypeForDuplicationCheck(Ty)})
.second;
}

public:
Expand Down
13 changes: 13 additions & 0 deletions lib/IDE/CompletionLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1940,6 +1940,19 @@ void CompletionLookup::onLookupNominalTypeMembers(NominalTypeDecl *NTD,
CompletionContext->LookedupNominalTypeNames.push_back(qualifiedName);
}

Type CompletionLookup::normalizeTypeForDuplicationCheck(Type Ty) {
return Ty.transform([](Type T) {
if (auto opaque = T->getAs<OpaqueTypeArchetypeType>()) {
/// Opaque type has a _invisible_ substitution map. Since IDE can't
/// differentiate them, replace it with empty substitution map.
return OpaqueTypeArchetypeType::get(opaque->getDecl(),
opaque->getInterfaceType(),
/*Substitutions=*/{});
}
return T;
});
}

void CompletionLookup::foundDecl(ValueDecl *D, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo) {
assert(Reason !=
Expand Down
71 changes: 30 additions & 41 deletions test/IDE/complete_opaque_result.swift
Original file line number Diff line number Diff line change
@@ -1,29 +1,5 @@
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GLOBAL_FUNC | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=GLOBAL_VAR | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_ASSOCIATEDTYPE | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_METHOD_REQUIREMENT | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_VAR_REQUIREMENT | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_SUBSCRIPT_REQUIREMENT | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_METHOD_EXTENSION | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_VAR_EXTENSION | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=PROTOCOL_SUBSCRIPT_EXTENSION | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_METHOD | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_VAR | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_SUBSCRIPT | %FileCheck %s -check-prefix=BEGINNING_WITH_SOME
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=STRUCT_TYPEALIAS_RHS | %FileCheck %s -check-prefix=BEGINNING_WITHOUT_SOME

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_TestClass | %FileCheck %s -check-prefix=OVERRIDE
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_TestStruct | %FileCheck %s -check-prefix=OVERRIDE
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_HasTypealias | %FileCheck %s -check-prefix=OVERRIDE_HasTypealias

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_TestProtocol_DOT | %FileCheck %s -check-prefix=POSTFIX_TestProtocol_DOT
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_TestProtocol_NODOT | %FileCheck %s -check-prefix=POSTFIX_TestProtocol_NODOT

// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=OVERRIDE_TestProtocol2 | %FileCheck %s -check-prefix=OVERRIDE_TestProtocol2
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=POSTFIX_ConcreteTestProtocol2 | %FileCheck %s -check-prefix=POSTFIX_ConcreteTestProtocol2
// RUN: %empty-directory(%t)
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t

protocol MyProtocol {
associatedtype Mistery
Expand Down Expand Up @@ -52,27 +28,27 @@ struct ConcreteMyProtocol : MyProtocol {
// BEGINNING_WITHOUT_SOME-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
// BEGINNING_WITHOUT_SOME-NOT: Keyword/None: some

func gloabalFunc() -> #^GLOBAL_FUNC^#
var globalVar: #^GLOBAL_VAR^#
func gloabalFunc() -> #^GLOBAL_FUNC?check=BEGINNING_WITH_SOME^#
var globalVar: #^GLOBAL_VAR?check=BEGINNING_WITHOUT_SOME^#

protocol SomeProto {
associatedtype protoAssocTy: #^PROTOCOL_ASSOCIATEDTYPE^#
func protoMethodReq() -> #^PROTOCOL_METHOD_REQUIREMENT^#
var protoVarReq: #^PROTOCOL_VAR_REQUIREMENT^#
subscript(req: Int) -> #^PROTOCOL_SUBSCRIPT_REQUIREMENT^#
associatedtype protoAssocTy: #^PROTOCOL_ASSOCIATEDTYPE?check=BEGINNING_WITHOUT_SOME^#
func protoMethodReq() -> #^PROTOCOL_METHOD_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
var protoVarReq: #^PROTOCOL_VAR_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
subscript(req: Int) -> #^PROTOCOL_SUBSCRIPT_REQUIREMENT?check=BEGINNING_WITHOUT_SOME^#
}

extension SomeProto {
func protoMethodExt() -> #^PROTOCOL_METHOD_EXTENSION^#
var protoVarExt: #^PROTOCOL_VAR_EXTENSION^#
subscript(ext: Int) -> #^PROTOCOL_SUBSCRIPT_EXTENSION^#
func protoMethodExt() -> #^PROTOCOL_METHOD_EXTENSION?check=BEGINNING_WITH_SOME^#
var protoVarExt: #^PROTOCOL_VAR_EXTENSION?check=BEGINNING_WITH_SOME^#
subscript(ext: Int) -> #^PROTOCOL_SUBSCRIPT_EXTENSION?check=BEGINNING_WITH_SOME^#
}

struct SomeStruct {
typealias TyAlias = #^STRUCT_TYPEALIAS_RHS^#
func structMethodExt() -> #^STRUCT_METHOD^#
var structVarExt: #^STRUCT_VAR^#
subscript(struct: Int) -> #^STRUCT_SUBSCRIPT^#
typealias TyAlias = #^STRUCT_TYPEALIAS_RHS?check=BEGINNING_WITHOUT_SOME^#
func structMethodExt() -> #^STRUCT_METHOD?check=BEGINNING_WITH_SOME^#
var structVarExt: #^STRUCT_VAR?check=BEGINNING_WITH_SOME^#
subscript(struct: Int) -> #^STRUCT_SUBSCRIPT?check=BEGINNING_WITH_SOME^#
}

// MARK: Conformance.
Expand Down Expand Up @@ -129,7 +105,7 @@ class TestClass :
HasAssocWithConstraintOnProto,
HasAssocWithSameTypeConstraint,
HasAssocWithConformanceConstraintGeneric {
#^OVERRIDE_TestClass^#
#^OVERRIDE_TestClass?check=OVERRIDE^#
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocPlain() -> AssocPlain {|};
// OVERRIDE-DAG: Decl[InstanceMethod]/Super: func returnAssocWithConformanceConstraint(fn: (Int) -> Int) -> some MyProtocol {|};
// OVERRIDE-DAG: Decl[InstanceVar]/Super: var valAssocWithSuperClassConstraint: some MyClass;
Expand All @@ -153,7 +129,7 @@ struct TestStruct :
HasAssocWithConstraintOnProto,
HasAssocWithSameTypeConstraint,
HasAssocWithConformanceConstraintGeneric {
#^OVERRIDE_TestStruct^#
#^OVERRIDE_TestStruct?check=OVERRIDE^#
}

class HasTypealias : HasAssocWithConformanceConstraint {
Expand Down Expand Up @@ -222,3 +198,16 @@ func testUseTestProtocol2(value: ConcreteTestProtocol2) {
// POSTFIX_ConcreteTestProtocol2-DAG: Decl[InstanceMethod]/Super: baz({#x: ConcreteTestProtocol2.Assoc#})[#(ConcreteTestProtocol2.Assoc) -> ConcreteTestProtocol2.Assoc#];
// POSTFIX_ConcreteTestProtocol2-DAG: Decl[InstanceMethod]/Super: inExt()[#ConcreteTestProtocol2.Assoc#];
}

struct Generic<T> {
func returnMyProto() -> some MyProtocol { ConcreteMyProtocol() }
}
func overloaded() -> Generic<Int> { fatalError() }
func overloaded() -> Generic<Float> { fatalError() }
// Tests that ambiguous doesn't result duplicated 'returnMyProto()'.
func testDupGenericReturningOpaque() {
overloaded().#^DupGenericReturningOpaque^#
// DupGenericReturningOpaque-NOT: returnMyProto()
// DupGenericReturningOpaque: Decl[InstanceMethod]/CurrNominal: returnMyProto()[#MyProtocol#]; name=returnMyProto()
// DupGenericReturningOpaque-NOT: returnMyProto()
}