Skip to content

Commit b63dd8b

Browse files
authored
Merge pull request swiftlang#34596 from rintaro/ide-completion-rdar71063455
[CodeCompletion] Deduplicate results in ExprContextInfo
2 parents 20f0d96 + d221f14 commit b63dd8b

File tree

3 files changed

+38
-7
lines changed

3 files changed

+38
-7
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4366,13 +4366,18 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
43664366

43674367
void getUnresolvedMemberCompletions(ArrayRef<Type> Types) {
43684368
NeedLeadingDot = !HaveDot;
4369+
4370+
SmallPtrSet<CanType, 4> seenTypes;
43694371
for (auto T : Types) {
4370-
if (!T)
4372+
if (!T || !seenTypes.insert(T->getCanonicalType()).second)
43714373
continue;
4374+
43724375
if (auto objT = T->getOptionalObjectType()) {
43734376
// If this is optional type, perform completion for the object type.
43744377
// i.e. 'let _: Enum??? = .enumMember' is legal.
4375-
getUnresolvedMemberCompletions(objT->lookThroughAllOptionalTypes());
4378+
objT = objT->lookThroughAllOptionalTypes();
4379+
if (seenTypes.insert(objT->getCanonicalType()).second)
4380+
getUnresolvedMemberCompletions(objT);
43764381

43774382
// Add 'nil' keyword with erasing '.' instruction.
43784383
unsigned bytesToErase = 0;

lib/IDE/ExprContextAnalysis.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -795,8 +795,8 @@ class ExprContextAnalyzer {
795795
bool MayNeedName = !HasName && !E->isImplicit() &&
796796
(isa<CallExpr>(E) | isa<SubscriptExpr>(E) ||
797797
isa<UnresolvedMemberExpr>(E));
798-
SmallPtrSet<TypeBase *, 4> seenTypes;
799-
llvm::SmallSet<std::pair<Identifier, TypeBase *>, 4> seenArgs;
798+
SmallPtrSet<CanType, 4> seenTypes;
799+
llvm::SmallSet<std::pair<Identifier, CanType>, 4> seenArgs;
800800
for (auto &typeAndDecl : Candidates) {
801801
DeclContext *memberDC = nullptr;
802802
if (typeAndDecl.Decl)
@@ -820,15 +820,16 @@ class ExprContextAnalyzer {
820820
paramList->get(Pos)->isVariadic());
821821

822822
if (paramType.hasLabel() && MayNeedName) {
823-
if (seenArgs.insert({paramType.getLabel(), ty.getPointer()}).second)
823+
if (seenArgs.insert({paramType.getLabel(), ty->getCanonicalType()})
824+
.second)
824825
recordPossibleParam(&paramType, !canSkip);
825826
} else {
826827
auto argTy = ty;
827828
if (paramType.isInOut())
828829
argTy = InOutType::get(argTy);
829830
else if (paramType.isAutoClosure() && argTy->is<AnyFunctionType>())
830831
argTy = argTy->castTo<AnyFunctionType>()->getResult();
831-
if (seenTypes.insert(argTy.getPointer()).second)
832+
if (seenTypes.insert(argTy->getCanonicalType()).second)
832833
recordPossibleType(argTy);
833834
}
834835
if (!canSkip)
@@ -837,7 +838,7 @@ class ExprContextAnalyzer {
837838
// If the argument position is out of expeceted number, indicate that
838839
// with optional nullptr param.
839840
if (Position >= Params.size()) {
840-
if (seenArgs.insert({Identifier(), nullptr}).second)
841+
if (seenArgs.insert({Identifier(), CanType()}).second)
841842
recordPossibleParam(nullptr, /*isRequired=*/false);
842843
}
843844
}

test/IDE/complete_unresolved_members.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AUTOCLOSURE_OPT | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
128128
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AUTOCLOSURE_FUNCTY | %FileCheck %s -check-prefix=UNRESOLVED_3
129129
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=AUTOCLOSURE_FUNCTY_OPT | %FileCheck %s -check-prefix=UNRESOLVED_3_OPT
130+
// RUN: %target-swift-ide-test -code-completion -source-filename %s -code-completion-token=SUGAR_TYPE | %FileCheck %s -check-prefix=SUGAR_TYPE
130131

131132
enum SomeEnum1 {
132133
case South
@@ -843,3 +844,27 @@ func testAutoclosreFuncTy(fn: (@autoclosure () -> SomeEnum1) -> Void, fnOpt: (@a
843844
fnOpt(.#^AUTOCLOSURE_FUNCTY_OPT^#)
844845
// Same as UNRESOLVED_3_OPT
845846
}
847+
848+
func testSameType() {
849+
typealias EnumAlias = SomeEnum1
850+
func testSugarType(_ arg: Optional<SomeEnum1>, arg2: Int8) {}
851+
func testSugarType(_ arg: SomeEnum1?, arg2: Int16) {}
852+
func testSugarType(_ arg: Optional<EnumAlias>, arg2: Int32) {}
853+
func testSugarType(_ arg: EnumAlias?, arg2: Int64) {}
854+
func testSugarType(_ arg: SomeEnum1, arg2: Int) {}
855+
func testSugarType(_ arg: EnumAlias, arg2: String) {}
856+
857+
testSugarType(.#^SUGAR_TYPE^#
858+
// Ensure results aren't duplicated.
859+
// SUGAR_TYPE: Begin completions, 9 items
860+
// SUGAR_TYPE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: South[#SomeEnum1#];
861+
// SUGAR_TYPE-DAG: Decl[EnumElement]/CurrNominal/TypeRelation[Identical]: North[#SomeEnum1#];
862+
// SUGAR_TYPE-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Invalid]: hash({#(self): SomeEnum1#})[#(into: inout Hasher) -> Void#];
863+
// SUGAR_TYPE-DAG: Keyword[nil]/None/Erase[1]/TypeRelation[Identical]: nil[#Optional<SomeEnum1>#];
864+
// SUGAR_TYPE-DAG: Decl[EnumElement]/CurrNominal/IsSystem/TypeRelation[Identical]: none[#Optional<SomeEnum1>#];
865+
// SUGAR_TYPE-DAG: Decl[EnumElement]/CurrNominal/IsSystem/TypeRelation[Identical]: some({#SomeEnum1#})[#Optional<SomeEnum1>#];
866+
// SUGAR_TYPE-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: map({#(self): Optional<SomeEnum1>#})[#((SomeEnum1) throws -> U) -> U?#];
867+
// SUGAR_TYPE-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem: flatMap({#(self): Optional<SomeEnum1>#})[#((SomeEnum1) throws -> U?) -> U?#];
868+
// SUGAR_TYPE-DAG: Decl[InstanceMethod]/CurrNominal/IsSystem/TypeRelation[Invalid]: hash({#(self): Optional<SomeEnum1>#})[#(into: inout Hasher) -> Void#];
869+
// SUGAR_TYPE: End completions
870+
}

0 commit comments

Comments
 (0)