Skip to content

[5.5][CodeCompletion] Don't check 'InvalidAsyncContext' for imported globals #37594

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
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
23 changes: 17 additions & 6 deletions lib/IDE/CodeCompletion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
bool FoundFunctionsWithoutFirstKeyword = false;

private:
bool isForCaching() const {
return Kind == LookupKind::ImportFromModule;
}

void foundFunction(const AbstractFunctionDecl *AFD) {
FoundFunctionCalls = true;
const DeclName Name = AFD->getName();
Expand Down Expand Up @@ -2588,7 +2592,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
}
bool implicitlyAsync = false;
analyzeActorIsolation(VD, VarType, implicitlyAsync, NotRecommended);
if (!NotRecommended && implicitlyAsync && !CanCurrDeclContextHandleAsync) {
if (!isForCaching() && !NotRecommended && implicitlyAsync &&
!CanCurrDeclContextHandleAsync) {
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
}

Expand Down Expand Up @@ -2930,7 +2935,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
else
addTypeAnnotation(Builder, AFT->getResult(), genericSig);

if (AFT->isAsync() && !CanCurrDeclContextHandleAsync) {
if (!isForCaching() && AFT->isAsync() && !CanCurrDeclContextHandleAsync) {
Builder.setNotRecommended(NotRecommendedReason::InvalidAsyncContext);
}
};
Expand Down Expand Up @@ -3044,7 +3049,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
bool implictlyAsync = false;
analyzeActorIsolation(FD, AFT, implictlyAsync, NotRecommended);

if (!NotRecommended && !IsImplicitlyCurriedInstanceMethod &&
if (!isForCaching() && !NotRecommended &&
!IsImplicitlyCurriedInstanceMethod &&
((AFT && AFT->isAsync()) || implictlyAsync) &&
!CanCurrDeclContextHandleAsync) {
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
Expand Down Expand Up @@ -3244,7 +3250,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
addTypeAnnotation(Builder, *Result, CD->getGenericSignatureOfContext());
}

if (ConstructorType->isAsync() && !CanCurrDeclContextHandleAsync) {
if (!isForCaching() && ConstructorType->isAsync() &&
!CanCurrDeclContextHandleAsync) {
Builder.setNotRecommended(NotRecommendedReason::InvalidAsyncContext);
}
};
Expand Down Expand Up @@ -3295,7 +3302,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
bool implictlyAsync = false;
analyzeActorIsolation(SD, subscriptType, implictlyAsync, NotRecommended);

if (!NotRecommended && implictlyAsync && !CanCurrDeclContextHandleAsync) {
if (!isForCaching() && !NotRecommended && implictlyAsync &&
!CanCurrDeclContextHandleAsync) {
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
}

Expand Down Expand Up @@ -7122,7 +7130,10 @@ void swift::ide::lookupCodeCompletionResultsFromModule(
CodeCompletionResultSink &targetSink, const ModuleDecl *module,
ArrayRef<std::string> accessPath, bool needLeadingDot,
const DeclContext *currDeclContext) {
CompletionLookup Lookup(targetSink, module->getASTContext(), currDeclContext);
// Consisitently use the SourceFile as the decl context, to avoid decl
// context specific behaviors.
auto *SF = currDeclContext->getParentSourceFile();
CompletionLookup Lookup(targetSink, module->getASTContext(), SF);
Lookup.lookupExternalModuleDecls(module, accessPath, needLeadingDot);
}

Expand Down
4 changes: 4 additions & 0 deletions lib/IDE/CodeCompletionCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,10 @@ static void writeCachedModule(llvm::raw_ostream &out,
endian::Writer LE(results, little);
for (CodeCompletionResult *R : V.Sink.Results) {
assert(!R->isArgumentLabels() && "Argument labels should not be cached");
assert(R->getNotRecommendedReason() !=
CodeCompletionResult::NotRecommendedReason::InvalidAsyncContext &&
"InvalidAsyncContext is decl context specific, cannot be cached");

// FIXME: compress bitfield
LE.write(static_cast<uint8_t>(R->getKind()));
if (R->getKind() == CodeCompletionResult::Declaration)
Expand Down
73 changes: 73 additions & 0 deletions test/IDE/complete_cache_notrecommended.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// REQUIRES: concurrency

// BEGIN MyModule.swift

public actor MyActor {
public init() {}
public func actorMethod() -> Int { 1 }

@available(*, deprecated)
public func deprecatedMethod() {}
}

public func globalAsyncFunc() async -> Int { 1 }

@available(*, deprecated)
public func deprecatedFunc() {}

// BEGIN App.swift
import MyModule

func testSync() -> Int{
#^GLOBAL_IN_SYNC^#
// FIXME: 'globalAsyncFunc()' *should* be "NotRecommended" because it's 'async'
// The curently behavior is due to completion cache. We should remember
// 'async'-ness in the cache. (rdar://78317170)

// GLOBAL_IN_SYNC: Begin completions
// GLOBAL_IN_SYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]: globalAsyncFunc()[' async'][#Int#];
// GLOBAL_IN_SYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]/NotRecommended: deprecatedFunc()[#Void#];
// GLOBAL_IN_SYNC-DAG: Decl[Class]/OtherModule[MyModule]: MyActor[#MyActor#];
// GLOBAL_IN_SYNC: End completions
}
func testAsync() async -> Int {
#^GLOBAL_IN_ASYNC^#
// GLOBAL_IN_ASYNC: Begin completions
// GLOBAL_IN_ASYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]: globalAsyncFunc()[' async'][#Int#];
// GLOBAL_IN_ASYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]/NotRecommended: deprecatedFunc()[#Void#];
// GLOBAL_IN_ASYNC-DAG: Decl[Class]/OtherModule[MyModule]: MyActor[#MyActor#];
// GLOBAL_IN_ASYNC: End completions
}
func testSyncMember(obj: MyActor) -> Int {
obj.#^MEMBER_IN_SYNC^#
// MEMBER_IN_SYNC: Begin completions, 4 items
// MEMBER_IN_SYNC-DAG: Keyword[self]/CurrNominal: self[#MyActor#];
// MEMBER_IN_SYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended/TypeRelation[Identical]: actorMethod()[' async'][#Int#];
// MEMBER_IN_SYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: deprecatedMethod()[' async'][#Void#];
// MEMBER_IN_SYNC-DAG: Decl[InstanceVar]/CurrNominal: unownedExecutor[#UnownedSerialExecutor#];
// MEMBER_IN_SYNC: End completions
}

func testSyncMember(obj: MyActor) async -> Int {
obj.#^MEMBER_IN_ASYNC^#
// MEMBER_IN_ASYNC: Begin completions, 4 items
// MEMBER_IN_ASYNC-DAG: Keyword[self]/CurrNominal: self[#MyActor#];
// MEMBER_IN_ASYNC-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: actorMethod()[' async'][#Int#];
// MEMBER_IN_ASYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: deprecatedMethod()[' async'][#Void#];
// MEMBER_IN_ASYNC-DAG: Decl[InstanceVar]/CurrNominal: unownedExecutor[#UnownedSerialExecutor#];
// MEMBER_IN_ASYNC: End completions
}

// RUN: %empty-directory(%t)
// RUN: %{python} %utils/split_file.py -o %t %s

// RUN: %empty-directory(%t/Modules)
// RUN: %target-swift-frontend -emit-module -module-name MyModule -o %t/Modules %t/MyModule.swift

// RUN: %empty-directory(%t/output)
// RUN: %empty-directory(%t/ccp)
// RUN: %empty-directory(%t/mcp)

// NOTE: Doing twice is to ensure that the completion cache is used.
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/App.swift -filecheck %raw-FileCheck -completion-output-dir %t/output -I %t/Modules -completion-cache-path %t/ccp -module-cache-path %t/mcp
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %t/App.swift -filecheck %raw-FileCheck -completion-output-dir %t/output -I %t/Modules -completion-cache-path %t/ccp -module-cache-path %t/mcp
2 changes: 1 addition & 1 deletion test/SourceKit/CodeComplete/complete_sort_order.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func test5() {
// STMT_1-LABEL: Results for filterText: ret [
// STMT_1-NEXT: return
// STMT_1-NEXT: retLocal
// STMT_1-NEXT: repeat
// STMT_1: repeat
// STMT_1: ]
// STMT_1-LABEL: Results for filterText: retur [
// STMT_1-NEXT: return
Expand Down