Skip to content

Commit 0ce1faa

Browse files
committed
[CodeCompletion] Don't check 'InvalidAsyncContext' for imported globals
'InvalidAsyncContext' depends on the decl context. That may case "sticky" not-recommended If it's cached for a non-async context. To workaround this, stop checking 'InvalidAsyncContext' when collecting completion items for caching. Also consistently use the 'SourceFile' as the decl context to avoid decl context specific behavior. rdar://78315441
1 parent 53264a6 commit 0ce1faa

File tree

4 files changed

+95
-7
lines changed

4 files changed

+95
-7
lines changed

lib/IDE/CodeCompletion.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,6 +1884,10 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
18841884
bool FoundFunctionsWithoutFirstKeyword = false;
18851885

18861886
private:
1887+
bool isForCaching() const {
1888+
return Kind == LookupKind::ImportFromModule;
1889+
}
1890+
18871891
void foundFunction(const AbstractFunctionDecl *AFD) {
18881892
FoundFunctionCalls = true;
18891893
const DeclName Name = AFD->getName();
@@ -2589,7 +2593,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
25892593
}
25902594
bool implicitlyAsync = false;
25912595
analyzeActorIsolation(VD, VarType, implicitlyAsync, NotRecommended);
2592-
if (!NotRecommended && implicitlyAsync && !CanCurrDeclContextHandleAsync) {
2596+
if (!isForCaching() && !NotRecommended && implicitlyAsync &&
2597+
!CanCurrDeclContextHandleAsync) {
25932598
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
25942599
}
25952600

@@ -2931,7 +2936,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
29312936
else
29322937
addTypeAnnotation(Builder, AFT->getResult(), genericSig);
29332938

2934-
if (AFT->isAsync() && !CanCurrDeclContextHandleAsync) {
2939+
if (!isForCaching() && AFT->isAsync() && !CanCurrDeclContextHandleAsync) {
29352940
Builder.setNotRecommended(NotRecommendedReason::InvalidAsyncContext);
29362941
}
29372942
};
@@ -3045,7 +3050,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
30453050
bool implictlyAsync = false;
30463051
analyzeActorIsolation(FD, AFT, implictlyAsync, NotRecommended);
30473052

3048-
if (!NotRecommended && !IsImplicitlyCurriedInstanceMethod &&
3053+
if (!isForCaching() && !NotRecommended &&
3054+
!IsImplicitlyCurriedInstanceMethod &&
30493055
((AFT && AFT->isAsync()) || implictlyAsync) &&
30503056
!CanCurrDeclContextHandleAsync) {
30513057
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
@@ -3245,7 +3251,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32453251
addTypeAnnotation(Builder, *Result, CD->getGenericSignatureOfContext());
32463252
}
32473253

3248-
if (ConstructorType->isAsync() && !CanCurrDeclContextHandleAsync) {
3254+
if (!isForCaching() && ConstructorType->isAsync() &&
3255+
!CanCurrDeclContextHandleAsync) {
32493256
Builder.setNotRecommended(NotRecommendedReason::InvalidAsyncContext);
32503257
}
32513258
};
@@ -3296,7 +3303,8 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
32963303
bool implictlyAsync = false;
32973304
analyzeActorIsolation(SD, subscriptType, implictlyAsync, NotRecommended);
32983305

3299-
if (!NotRecommended && implictlyAsync && !CanCurrDeclContextHandleAsync) {
3306+
if (!isForCaching() && !NotRecommended && implictlyAsync &&
3307+
!CanCurrDeclContextHandleAsync) {
33003308
NotRecommended = NotRecommendedReason::InvalidAsyncContext;
33013309
}
33023310

@@ -7123,7 +7131,10 @@ void swift::ide::lookupCodeCompletionResultsFromModule(
71237131
CodeCompletionResultSink &targetSink, const ModuleDecl *module,
71247132
ArrayRef<std::string> accessPath, bool needLeadingDot,
71257133
const DeclContext *currDeclContext) {
7126-
CompletionLookup Lookup(targetSink, module->getASTContext(), currDeclContext);
7134+
// Consisitently use the SourceFile as the decl context, to avoid decl
7135+
// context specific behaviors.
7136+
auto *SF = currDeclContext->getParentSourceFile();
7137+
CompletionLookup Lookup(targetSink, module->getASTContext(), SF);
71277138
Lookup.lookupExternalModuleDecls(module, accessPath, needLeadingDot);
71287139
}
71297140

lib/IDE/CodeCompletionCache.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,10 @@ static void writeCachedModule(llvm::raw_ostream &out,
342342
endian::Writer LE(results, little);
343343
for (CodeCompletionResult *R : V.Sink.Results) {
344344
assert(!R->isArgumentLabels() && "Argument labels should not be cached");
345+
assert(R->getNotRecommendedReason() !=
346+
CodeCompletionResult::NotRecommendedReason::InvalidAsyncContext &&
347+
"InvalidAsyncContext is decl context specific, cannot be cached");
348+
345349
// FIXME: compress bitfield
346350
LE.write(static_cast<uint8_t>(R->getKind()));
347351
if (R->getKind() == CodeCompletionResult::Declaration)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// REQUIRES: concurrency
2+
3+
// BEGIN MyModule.swift
4+
5+
public actor MyActor {
6+
public init() {}
7+
public func actorMethod() -> Int { 1 }
8+
9+
@available(*, deprecated)
10+
public func deprecatedMethod() {}
11+
}
12+
13+
public func globalAsyncFunc() async -> Int { 1 }
14+
15+
@available(*, deprecated)
16+
public func deprecatedFunc() {}
17+
18+
// BEGIN App.swift
19+
import MyModule
20+
21+
func testSync() -> Int{
22+
#^GLOBAL_IN_SYNC^#
23+
// FIXME: 'globalAsyncFunc()' *should* be "NotRecommended" because it's 'async'
24+
// The curently behavior is due to completion cache. We should remember
25+
// 'async'-ness in the cache. (rdar://78317170)
26+
27+
// GLOBAL_IN_SYNC: Begin completions
28+
// GLOBAL_IN_SYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]: globalAsyncFunc()[' async'][#Int#];
29+
// GLOBAL_IN_SYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]/NotRecommended: deprecatedFunc()[#Void#];
30+
// GLOBAL_IN_SYNC-DAG: Decl[Class]/OtherModule[MyModule]: MyActor[#MyActor#];
31+
// GLOBAL_IN_SYNC: End completions
32+
}
33+
func testAsync() async -> Int {
34+
#^GLOBAL_IN_ASYNC^#
35+
// GLOBAL_IN_ASYNC: Begin completions
36+
// GLOBAL_IN_ASYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]: globalAsyncFunc()[' async'][#Int#];
37+
// GLOBAL_IN_ASYNC-DAG: Decl[FreeFunction]/OtherModule[MyModule]/NotRecommended: deprecatedFunc()[#Void#];
38+
// GLOBAL_IN_ASYNC-DAG: Decl[Class]/OtherModule[MyModule]: MyActor[#MyActor#];
39+
// GLOBAL_IN_ASYNC: End completions
40+
}
41+
func testSyncMember(obj: MyActor) -> Int {
42+
obj.#^MEMBER_IN_SYNC^#
43+
// MEMBER_IN_SYNC: Begin completions, 4 items
44+
// MEMBER_IN_SYNC-DAG: Keyword[self]/CurrNominal: self[#MyActor#];
45+
// MEMBER_IN_SYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended/TypeRelation[Identical]: actorMethod()[' async'][#Int#];
46+
// MEMBER_IN_SYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: deprecatedMethod()[' async'][#Void#];
47+
// MEMBER_IN_SYNC-DAG: Decl[InstanceVar]/CurrNominal: unownedExecutor[#UnownedSerialExecutor#];
48+
// MEMBER_IN_SYNC: End completions
49+
}
50+
51+
func testSyncMember(obj: MyActor) async -> Int {
52+
obj.#^MEMBER_IN_ASYNC^#
53+
// MEMBER_IN_ASYNC: Begin completions, 4 items
54+
// MEMBER_IN_ASYNC-DAG: Keyword[self]/CurrNominal: self[#MyActor#];
55+
// MEMBER_IN_ASYNC-DAG: Decl[InstanceMethod]/CurrNominal/TypeRelation[Identical]: actorMethod()[' async'][#Int#];
56+
// MEMBER_IN_ASYNC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: deprecatedMethod()[' async'][#Void#];
57+
// MEMBER_IN_ASYNC-DAG: Decl[InstanceVar]/CurrNominal: unownedExecutor[#UnownedSerialExecutor#];
58+
// MEMBER_IN_ASYNC: End completions
59+
}
60+
61+
// RUN: %empty-directory(%t)
62+
// RUN: %{python} %utils/split_file.py -o %t %s
63+
64+
// RUN: %empty-directory(%t/Modules)
65+
// RUN: %target-swift-frontend -emit-module -module-name MyModule -o %t/Modules %t/MyModule.swift
66+
67+
// RUN: %empty-directory(%t/output)
68+
// RUN: %empty-directory(%t/ccp)
69+
// RUN: %empty-directory(%t/mcp)
70+
71+
// NOTE: Doing twice is to ensure that the completion cache is used.
72+
// 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
73+
// 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

test/SourceKit/CodeComplete/complete_sort_order.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func test5() {
7777
// STMT_1-LABEL: Results for filterText: ret [
7878
// STMT_1-NEXT: return
7979
// STMT_1-NEXT: retLocal
80-
// STMT_1-NEXT: repeat
80+
// STMT_1: repeat
8181
// STMT_1: ]
8282
// STMT_1-LABEL: Results for filterText: retur [
8383
// STMT_1-NEXT: return

0 commit comments

Comments
 (0)