Skip to content

Commit 532b249

Browse files
committed
[CodeCompletion] Handle "unsafe" global actor isolation
For 'unsafe' global actor isolation, implicit "async" happens only if * The context adopted concurrency feature * Not '-warn-concurrency' specified rdar://80907499 (cherry picked from commit 6c4eaa1)
1 parent 42cbd82 commit 532b249

File tree

5 files changed

+225
-2
lines changed

5 files changed

+225
-2
lines changed

include/swift/Sema/IDETypeChecking.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@ namespace swift {
283283
/// for a Fix-It that adds a new build* function to a result builder.
284284
std::tuple<SourceLoc, std::string, Type>
285285
determineResultBuilderBuildFixItInfo(NominalTypeDecl *builder);
286+
287+
/// Just a proxy to swift::contextUsesConcurrencyFeatures() from lib/IDE code.
288+
bool completionContextUsesConcurrencyFeatures(const DeclContext *dc);
286289
}
287290

288291
#endif

lib/IDE/CodeCompletion.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2642,6 +2642,7 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26422642
void analyzeActorIsolation(const ValueDecl *VD, Type T, bool &implicitlyAsync,
26432643
Optional<NotRecommendedReason> &NotRecommended) {
26442644
auto isolation = getActorIsolation(const_cast<ValueDecl *>(VD));
2645+
auto &ctx = VD->getASTContext();
26452646

26462647
switch (isolation.getKind()) {
26472648
case ActorIsolation::ActorInstance: {
@@ -2651,8 +2652,16 @@ class CompletionLookup final : public swift::VisibleDeclConsumer {
26512652
}
26522653
break;
26532654
}
2654-
case ActorIsolation::GlobalActor:
2655-
case ActorIsolation::GlobalActorUnsafe: {
2655+
case ActorIsolation::GlobalActorUnsafe:
2656+
// For "unsafe" global actor isolation, automatic 'async' only happens
2657+
// if the context has adopted concurrency.
2658+
if (!CanCurrDeclContextHandleAsync &&
2659+
!completionContextUsesConcurrencyFeatures(CurrDeclContext) &&
2660+
!ctx.LangOpts.WarnConcurrency) {
2661+
return;
2662+
}
2663+
LLVM_FALLTHROUGH;
2664+
case ActorIsolation::GlobalActor: {
26562665
auto contextIsolation = getActorIsolationOfContext(
26572666
const_cast<DeclContext *>(CurrDeclContext));
26582667
if (contextIsolation != isolation) {

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/AST/NameLookupRequests.h"
2626
#include "swift/AST/TypeCheckRequests.h"
2727
#include "swift/AST/TypeVisitor.h"
28+
#include "swift/Sema/IDETypeChecking.h"
2829

2930
using namespace swift;
3031

@@ -3820,3 +3821,7 @@ AnyFunctionType *swift::applyGlobalActorType(
38203821
return FunctionType::get(
38213822
fnType->getParams(), Type(innerFnType), fnType->getExtInfo());
38223823
}
3824+
3825+
bool swift::completionContextUsesConcurrencyFeatures(const DeclContext *dc) {
3826+
return contextUsesConcurrencyFeatures(dc);
3827+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency
2+
3+
// SAFE_NOTREC: Begin completions, 2 items
4+
// SAFE_NOTREC-DAG: Keyword[self]/CurrNominal: self[#SafelyIsolatedCls#];
5+
// SAFE_NOTREC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: method()[' async'][#Void#];
6+
// SAFE_NOTREC: End completions
7+
8+
// UNSAFE_NOTREC: Begin completions, 2 items
9+
// UNSAFE_NOTREC-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
10+
// UNSAFE_NOTREC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: method()[' async'][#Void#];
11+
// UNSAFE_NOTREC: End completions
12+
13+
// SAFE_OK: Begin completions, 2 items
14+
// SAFE_OK-DAG: Keyword[self]/CurrNominal: self[#SafelyIsolatedCls#];
15+
// SAFE_OK-DAG: Decl[InstanceMethod]/CurrNominal: method()[' async'][#Void#];
16+
// SAFE_OK: End completions
17+
18+
// UNSAFE_OK: Begin completions, 2 items
19+
// UNSAFE_OK-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
20+
// UNSAFE_OK-DAG: Decl[InstanceMethod]/CurrNominal: method()[' async'][#Void#];
21+
// UNSAFE_OK: End completions
22+
23+
// UNSAFE_OK_SYNC: Begin completions, 2 items
24+
// UNSAFE_OK_SYNC-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
25+
// UNSAFE_OK_SYNC-DAG: Decl[InstanceMethod]/CurrNominal: method()[#Void#];
26+
// UNSAFE_OK_SYNC: End completions
27+
28+
@globalActor
29+
actor MyGlobalActor {
30+
static let shared = MyGlobalActor()
31+
}
32+
33+
@MyGlobalActor(unsafe)
34+
class UnsafelyIsolatedCls {
35+
func method()
36+
}
37+
38+
@MyGlobalActor
39+
class SafelyIsolatedCls {
40+
func method()
41+
}
42+
43+
class TestNormal {
44+
func testSync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
45+
s.#^IN_METHOD_SYNC_SAFE?check=SAFE_NOTREC^#
46+
u.#^IN_METHOD_SYNC_UNSAFE?check=UNSAFE_OK_SYNC^#
47+
}
48+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
49+
s.#^IN_METHOD_ASYNC_SAFE?check=SAFE_OK^#
50+
u.#^IN_METHOD_ASYNC_UNSAFE?check=UNSAFE_OK^#
51+
}
52+
}
53+
54+
func testSync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
55+
s.#^IN_FUNC_SYNC_SAFE?check=SAFE_NOTREC^#
56+
u.#^IN_FUNC_SYNC_UNSAFE?check=UNSAFE_OK_SYNC^#
57+
}
58+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
59+
s.#^IN_FUNC_ASYNC_SAFE?check=SAFE_OK^#
60+
u.#^IN_FUNC_ASYNC_UNSAFE?check=UNSAFE_OK^#
61+
}
62+
63+
func testClosure(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
64+
func receiverSync(fn: () -> Void) {}
65+
func receiverAsync(fn: () async -> Void) {}
66+
67+
receiverSync {
68+
dummy;
69+
s.#^IN_CLOSURE_SYNC_SAFE?check=SAFE_NOTREC^#
70+
u.#^IN_CLOSURE_SYNC_UNSAFE?check=UNSAFE_OK_SYNC^#
71+
}
72+
73+
receiverAsync {
74+
dummy;
75+
s.#^IN_CLOSURE_ASYNC_SAFE?check=SAFE_OK^#
76+
u.#^IN_CLOSURE_ASYNC_UNSAFE?check=UNSAFE_OK^#
77+
}
78+
}
79+
80+
actor TestActor {
81+
func test(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
82+
s.#^IN_ACTOR_SYNC_SAFE?check=SAFE_NOTREC^#
83+
u.#^IN_ACTOR_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
84+
}
85+
86+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
87+
s.#^IN_ACTOR_ASYNC_SAFE?check=SAFE_OK^#
88+
u.#^IN_ACTOR_ASYNC_UNSAFE?check=UNSAFE_OK^#
89+
}
90+
}
91+
92+
@MainActor
93+
class TestMainActorIsolated {
94+
func test(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
95+
s.#^IN_GLOBALACTOR_SYNC_SAFE?check=SAFE_NOTREC^#
96+
u.#^IN_GLOBALACTOR_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
97+
}
98+
99+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
100+
s.#^IN_GLOBALACTOR_ASYNC_SAFE?check=SAFE_OK^#
101+
u.#^IN_GLOBALACTOR_ASYNC_UNSAFE?check=UNSAFE_OK^#
102+
}
103+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %target-swift-ide-test -batch-code-completion -source-filename %s -filecheck %raw-FileCheck -completion-output-dir %t -enable-experimental-concurrency -warn-concurrency
2+
3+
// SAFE_NOTREC: Begin completions, 2 items
4+
// SAFE_NOTREC-DAG: Keyword[self]/CurrNominal: self[#SafelyIsolatedCls#];
5+
// SAFE_NOTREC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: method()[' async'][#Void#];
6+
// SAFE_NOTREC: End completions
7+
8+
// UNSAFE_NOTREC: Begin completions, 2 items
9+
// UNSAFE_NOTREC-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
10+
// UNSAFE_NOTREC-DAG: Decl[InstanceMethod]/CurrNominal/NotRecommended: method()[' async'][#Void#];
11+
// UNSAFE_NOTREC: End completions
12+
13+
// SAFE_OK: Begin completions, 2 items
14+
// SAFE_OK-DAG: Keyword[self]/CurrNominal: self[#SafelyIsolatedCls#];
15+
// SAFE_OK-DAG: Decl[InstanceMethod]/CurrNominal: method()[' async'][#Void#];
16+
// SAFE_OK: End completions
17+
18+
// UNSAFE_OK: Begin completions, 2 items
19+
// UNSAFE_OK-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
20+
// UNSAFE_OK-DAG: Decl[InstanceMethod]/CurrNominal: method()[' async'][#Void#];
21+
// UNSAFE_OK: End completions
22+
23+
// UNSAFE_OK_SYNC: Begin completions, 2 items
24+
// UNSAFE_OK_SYNC-DAG: Keyword[self]/CurrNominal: self[#UnsafelyIsolatedCls#];
25+
// UNSAFE_OK_SYNC-DAG: Decl[InstanceMethod]/CurrNominal: method()[#Void#];
26+
// UNSAFE_OK_SYNC: End completions
27+
28+
@globalActor
29+
actor MyGlobalActor {
30+
static let shared = MyGlobalActor()
31+
}
32+
33+
@MyGlobalActor(unsafe)
34+
class UnsafelyIsolatedCls {
35+
func method()
36+
}
37+
38+
@MyGlobalActor
39+
class SafelyIsolatedCls {
40+
func method()
41+
}
42+
43+
class TestNormal {
44+
func testSync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
45+
s.#^IN_METHOD_SYNC_SAFE?check=SAFE_NOTREC^#
46+
u.#^IN_METHOD_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
47+
}
48+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
49+
s.#^IN_METHOD_ASYNC_SAFE?check=SAFE_OK^#
50+
u.#^IN_METHOD_ASYNC_UNSAFE?check=UNSAFE_OK^#
51+
}
52+
}
53+
54+
func testSync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
55+
s.#^IN_FUNC_SYNC_SAFE?check=SAFE_NOTREC^#
56+
u.#^IN_FUNC_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
57+
}
58+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
59+
s.#^IN_FUNC_ASYNC_SAFE?check=SAFE_OK^#
60+
u.#^IN_FUNC_ASYNC_UNSAFE?check=UNSAFE_OK^#
61+
}
62+
63+
func testClosure(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
64+
func receiverSync(fn: () -> Void) {}
65+
func receiverAsync(fn: () async -> Void) {}
66+
67+
receiverSync {
68+
dummy;
69+
s.#^IN_CLOSURE_SYNC_SAFE?check=SAFE_NOTREC^#
70+
u.#^IN_CLOSURE_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
71+
}
72+
73+
receiverAsync {
74+
dummy;
75+
s.#^IN_CLOSURE_ASYNC_SAFE?check=SAFE_OK^#
76+
u.#^IN_CLOSURE_ASYNC_UNSAFE?check=UNSAFE_OK^#
77+
}
78+
}
79+
80+
actor TestActor {
81+
func test(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
82+
s.#^IN_ACTOR_SYNC_SAFE?check=SAFE_NOTREC^#
83+
u.#^IN_ACTOR_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
84+
}
85+
86+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
87+
s.#^IN_ACTOR_ASYNC_SAFE?check=SAFE_OK^#
88+
u.#^IN_ACTOR_ASYNC_UNSAFE?check=UNSAFE_OK^#
89+
}
90+
}
91+
92+
@MainActor
93+
class TestMainActorIsolated {
94+
func test(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) {
95+
s.#^IN_GLOBALACTOR_SYNC_SAFE?check=SAFE_NOTREC^#
96+
u.#^IN_GLOBALACTOR_SYNC_UNSAFE?check=UNSAFE_NOTREC^#
97+
}
98+
99+
func testAsync(s: SafelyIsolatedCls, u: UnsafelyIsolatedCls) async {
100+
s.#^IN_GLOBALACTOR_ASYNC_SAFE?check=SAFE_OK^#
101+
u.#^IN_GLOBALACTOR_ASYNC_UNSAFE?check=UNSAFE_OK^#
102+
}
103+
}

0 commit comments

Comments
 (0)