@@ -1813,6 +1813,9 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
18131813 bool PreferFunctionReferencesToCalls = false ;
18141814 bool HaveLeadingSpace = false ;
18151815
1816+ bool CheckForDuplicates = false ;
1817+ llvm::DenseSet<std::pair<const Decl *, Type>> PreviouslySeen;
1818+
18161819 bool IncludeInstanceMembers = false ;
18171820
18181821 // / True if we are code completing inside a static method.
@@ -1998,6 +2001,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
19982001 IsKeyPathExpr = true ;
19992002 }
20002003
2004+ void shouldCheckForDuplicates (bool value = true ) {
2005+ CheckForDuplicates = value;
2006+ }
2007+
20012008 void setIsSwiftKeyPathExpr (bool onRoot) {
20022009 IsSwiftKeyPathExpr = true ;
20032010 IsAfterSwiftKeyPathRoot = onRoot;
@@ -2895,8 +2902,13 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
28952902 IsImplicitlyCurriedInstanceMethod = isImplicitlyCurriedInstanceMethod (FD);
28962903
28972904 // Strip off '(_ self: Self)' if needed.
2898- if (AFT && !IsImplicitlyCurriedInstanceMethod)
2905+ if (AFT && !IsImplicitlyCurriedInstanceMethod) {
28992906 AFT = AFT->getResult ()->getAs <AnyFunctionType>();
2907+
2908+ // Check for duplicates with the adjusted type too.
2909+ if (isDuplicate (FD, AFT))
2910+ return ;
2911+ }
29002912 }
29012913
29022914 bool trivialTrailingClosure = false ;
@@ -3369,10 +3381,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33693381 DynamicLookupInfo dynamicLookupInfo) {
33703382 auto funcTy =
33713383 getTypeOfMember (AFD, dynamicLookupInfo)->getAs <AnyFunctionType>();
3372- if (funcTy && AFD->getDeclContext ()->isTypeContext () &&
3373- !isImplicitlyCurriedInstanceMethod (AFD)) {
3384+ bool dropCurryLevel = funcTy && AFD->getDeclContext ()->isTypeContext () &&
3385+ !isImplicitlyCurriedInstanceMethod (AFD);
3386+ if (dropCurryLevel)
33743387 funcTy = funcTy->getResult ()->getAs <AnyFunctionType>();
3375- }
33763388
33773389 bool useFunctionReference = PreferFunctionReferencesToCalls;
33783390 if (!useFunctionReference && funcTy) {
@@ -3384,6 +3396,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
33843396 if (!useFunctionReference)
33853397 return false ;
33863398
3399+ // Check for duplicates with the adjusted type too.
3400+ if (dropCurryLevel && isDuplicate (AFD, funcTy))
3401+ return true ;
3402+
33873403 CommandWordsPairs Pairs;
33883404 CodeCompletionResultBuilder Builder (
33893405 Sink, CodeCompletionResult::ResultKind::Declaration,
@@ -3421,6 +3437,29 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34213437 return true ;
34223438 }
34233439
3440+ private:
3441+
3442+ // / Returns true if duplicate checking is enabled (via
3443+ // / \c shouldCheckForDuplicates) and this decl + type combination has been
3444+ // / checked previously. Returns false otherwise.
3445+ bool isDuplicate (const ValueDecl *D, Type Ty) {
3446+ if (!CheckForDuplicates)
3447+ return false ;
3448+ return !PreviouslySeen.insert ({D, Ty}).second ;
3449+ }
3450+
3451+ // / Returns true if duplicate checking is enabled (via
3452+ // / \c shouldCheckForDuplicates) and this decl has been checked previously
3453+ // / with the type according to \c getTypeOfMember. Returns false otherwise.
3454+ bool isDuplicate (const ValueDecl *D, DynamicLookupInfo dynamicLookupInfo) {
3455+ if (!CheckForDuplicates)
3456+ return false ;
3457+ Type Ty = getTypeOfMember (D, dynamicLookupInfo);
3458+ return !PreviouslySeen.insert ({D, Ty}).second ;
3459+ }
3460+
3461+ public:
3462+
34243463 // Implement swift::VisibleDeclConsumer.
34253464 void foundDecl (ValueDecl *D, DeclVisibilityKind Reason,
34263465 DynamicLookupInfo dynamicLookupInfo) override {
@@ -3436,6 +3475,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
34363475
34373476 if (IsSwiftKeyPathExpr && !SwiftKeyPathFilter (D, Reason))
34383477 return ;
3478+
3479+ // If we've seen this decl+type before (possible when multiple lookups are
3480+ // performed e.g. because of ambiguous base types), bail.
3481+ if (isDuplicate (D, dynamicLookupInfo))
3482+ return ;
34393483
34403484 // FIXME(InterfaceTypeRequest): Remove this.
34413485 (void )D->getInterfaceType ();
@@ -3526,6 +3570,11 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
35263570 Type funcType = getTypeOfMember (FD, dynamicLookupInfo)
35273571 ->castTo <AnyFunctionType>()
35283572 ->getResult ();
3573+
3574+ // Check for duplicates with the adjusted type too.
3575+ if (isDuplicate (FD, funcType))
3576+ return ;
3577+
35293578 addFunctionCallPattern (
35303579 funcType->castTo <AnyFunctionType>(), FD,
35313580 getSemanticContext (FD, Reason, dynamicLookupInfo));
@@ -6039,6 +6088,7 @@ void deliverDotExprResults(
60396088 Lookup.setPreferFunctionReferencesToCalls ();
60406089 }
60416090
6091+ Lookup.shouldCheckForDuplicates (Results.size () > 1 );
60426092 for (auto &Result: Results) {
60436093 Lookup.setIsStaticMetatype (Result.BaseIsStaticMetaType );
60446094 Lookup.getPostfixKeywordCompletions (Result.BaseTy , BaseExpr);
0 commit comments