Skip to content

Commit 0c675c7

Browse files
committed
Improve error messages for implicitly-async in sync contexts
when an expression that would be validly considered implicitly-async appears within a sync context, we try to be a bit more specific about the problem being that it's a sync context.
1 parent 4ba396a commit 0c675c7

File tree

5 files changed

+58
-35
lines changed

5 files changed

+58
-35
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4298,20 +4298,21 @@ ERROR(actor_isolated_mutating_func,none,
42984298
"cannot call mutating async function %0 on actor-isolated %1 %2",
42994299
(DeclName, DescriptiveDeclKind, DeclName))
43004300
ERROR(actor_isolated_global_actor_context,none,
4301-
"actor-isolated %0 %1 can not be referenced from context of global "
4302-
"actor %2",
4303-
(DescriptiveDeclKind, DeclName, Type))
4301+
"actor-isolated %0 %1 can not be %select{referenced|mutated|used 'inout'}3 "
4302+
"from%select{| synchronous}4 context of global actor %2",
4303+
(DescriptiveDeclKind, DeclName, Type, unsigned, bool))
43044304
ERROR(global_actor_from_instance_actor_context,none,
4305-
"%0 %1 isolated to global actor %2 can not be %select{referenced|mutated|used 'inout'}4 from actor %3",
4306-
(DescriptiveDeclKind, DeclName, Type, DeclName, unsigned))
4305+
"%0 %1 isolated to global actor %2 can not be %select{referenced|mutated|used 'inout'}4"
4306+
" from actor %3 %select{|in a synchronous context}5",
4307+
(DescriptiveDeclKind, DeclName, Type, DeclName, unsigned, bool))
43074308
ERROR(global_actor_from_other_global_actor_context,none,
43084309
"%0 %1 isolated to global actor %2 can not be %select{referenced|mutated|used 'inout'}4"
4309-
" from different global actor %3",
4310-
(DescriptiveDeclKind, DeclName, Type, Type, unsigned))
4310+
" from different global actor %3 %select{|in a synchronous context}5",
4311+
(DescriptiveDeclKind, DeclName, Type, Type, unsigned, bool))
43114312
ERROR(global_actor_from_nonactor_context,none,
43124313
"%0 %1 isolated to global actor %2 can not be %select{referenced|mutated|used 'inout'}4"
4313-
" from %select{this|an '@actorIndependent'}3 context",
4314-
(DescriptiveDeclKind, DeclName, Type, bool, unsigned))
4314+
" from %select{this|an '@actorIndependent'}3%select{| synchronous}5 context",
4315+
(DescriptiveDeclKind, DeclName, Type, bool, unsigned, bool))
43154316
ERROR(actor_isolated_partial_apply,none,
43164317
"actor-isolated %0 %1 can not be partially applied",
43174318
(DescriptiveDeclKind, DeclName))

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,22 +1570,26 @@ namespace {
15701570
AsyncMarkingResult tryMarkImplicitlyAsync(SourceLoc declLoc,
15711571
ConcreteDeclRef concDeclRef,
15721572
Expr* context) {
1573-
// If our current context isn't an asynchronous one, don't
1574-
if (!isInAsynchronousContext())
1575-
return AsyncMarkingResult::NotFound;
1576-
15771573
ValueDecl *decl = concDeclRef.getDecl();
15781574
AsyncMarkingResult result = AsyncMarkingResult::NotFound;
15791575

15801576
// is it an access to a property?
15811577
if (isPropOrSubscript(decl)) {
15821578
if (auto declRef = dyn_cast_or_null<DeclRefExpr>(context)) {
15831579
if (usageEnv(declRef) == VarRefUseEnv::Read) {
1580+
1581+
if (!isInAsynchronousContext())
1582+
return AsyncMarkingResult::SyncContext;
1583+
15841584
declRef->setImplicitlyAsync(true);
15851585
result = AsyncMarkingResult::FoundAsync;
15861586
}
15871587
} else if (auto lookupExpr = dyn_cast_or_null<LookupExpr>(context)) {
15881588
if (usageEnv(lookupExpr) == VarRefUseEnv::Read) {
1589+
1590+
if (!isInAsynchronousContext())
1591+
return AsyncMarkingResult::SyncContext;
1592+
15891593
lookupExpr->setImplicitlyAsync(true);
15901594
result = AsyncMarkingResult::FoundAsync;
15911595
}
@@ -1595,6 +1599,10 @@ namespace {
15951599
isa<AbstractFunctionDecl>(decl)) {
15961600
// actor-isolated non-isolated-self calls are implicitly async
15971601
// and thus OK.
1602+
1603+
if (!isInAsynchronousContext())
1604+
return AsyncMarkingResult::SyncContext;
1605+
15981606
markNearestCallAsImplicitlyAsync();
15991607
result = AsyncMarkingResult::FoundAsync;
16001608

@@ -1609,6 +1617,10 @@ namespace {
16091617
if (auto memberRef = findMemberReference(fn)) {
16101618
auto concDecl = memberRef->first;
16111619
if (decl == concDecl.getDecl() && !apply->implicitlyAsync()) {
1620+
1621+
if (!isInAsynchronousContext())
1622+
return AsyncMarkingResult::SyncContext;
1623+
16121624
// then this ValueDecl appears as the called value of the ApplyExpr.
16131625
markNearestCallAsImplicitlyAsync();
16141626
result = AsyncMarkingResult::FoundAsync;
@@ -1664,7 +1676,7 @@ namespace {
16641676
ctx.Diags.diagnose(loc, diag::global_actor_from_instance_actor_context,
16651677
value->getDescriptiveKind(), value->getName(),
16661678
globalActor, contextIsolation.getActor()->getName(),
1667-
useKind);
1679+
useKind, result == AsyncMarkingResult::SyncContext);
16681680
noteIsolatedActorMember(value, context);
16691681
return true;
16701682
}
@@ -1684,7 +1696,8 @@ namespace {
16841696
ctx.Diags.diagnose(
16851697
loc, diag::global_actor_from_other_global_actor_context,
16861698
value->getDescriptiveKind(), value->getName(), globalActor,
1687-
contextIsolation.getGlobalActor(), useKind);
1699+
contextIsolation.getGlobalActor(), useKind,
1700+
result == AsyncMarkingResult::SyncContext);
16881701
noteIsolatedActorMember(value, context);
16891702
return true;
16901703
}
@@ -1704,7 +1717,8 @@ namespace {
17041717
ctx.Diags.diagnose(loc, diag::global_actor_from_nonactor_context,
17051718
value->getDescriptiveKind(), value->getName(),
17061719
globalActor,
1707-
/*actorIndependent=*/true, useKind);
1720+
/*actorIndependent=*/true, useKind,
1721+
result == AsyncMarkingResult::SyncContext);
17081722
noteIsolatedActorMember(value, context);
17091723
return true;
17101724
}
@@ -1723,7 +1737,8 @@ namespace {
17231737
ctx.Diags.diagnose(
17241738
loc, diag::global_actor_from_nonactor_context,
17251739
value->getDescriptiveKind(), value->getName(), globalActor,
1726-
/*actorIndependent=*/false, useKind);
1740+
/*actorIndependent=*/false, useKind,
1741+
result == AsyncMarkingResult::SyncContext);
17271742
}
17281743
noteIsolatedActorMember(value, context);
17291744
};
@@ -2029,10 +2044,14 @@ namespace {
20292044

20302045
// The 'self' is for a member that's part of a global actor, which
20312046
// means we cannot refer to actor-isolated state.
2047+
auto useKind = static_cast<unsigned>(
2048+
kindOfUsage(member, context).getValueOr(VarRefUseEnv::Read));
20322049
ctx.Diags.diagnose(memberLoc,
20332050
diag::actor_isolated_global_actor_context,
20342051
member->getDescriptiveKind(), member->getName(),
2035-
contextIsolation.getGlobalActor());
2052+
contextIsolation.getGlobalActor(), useKind,
2053+
result == AsyncMarkingResult::SyncContext
2054+
);
20362055
noteIsolatedActorMember(member, context);
20372056
return true;
20382057
}

test/Concurrency/actor_isolation.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,10 @@ actor MyActor: MySuperActor {
5151
let point : Point = Point()
5252

5353
@MainActor
54-
var name : String = "koala"
54+
var name : String = "koala" // expected-note{{property declared here}}
5555

56-
// FIXME: if you take the 'async' off of this, you get a very confusing error message.
57-
func accessProp() async -> String {
58-
return await self.name
56+
func accessProp() -> String {
57+
return self.name // expected-error{{property 'name' isolated to global actor 'MainActor' can not be referenced from actor 'MyActor' in a synchronous context}}
5958
}
6059

6160
class func synchronousClass() { }
@@ -124,7 +123,7 @@ extension MyActor {
124123
_ = synchronous() // expected-error{{actor-isolated instance method 'synchronous()' can not be referenced from an '@actorIndependent' context}}
125124

126125
// Global actors
127-
syncGlobalActorFunc() /// expected-error{{global function 'syncGlobalActorFunc()' isolated to global actor 'SomeGlobalActor' can not be referenced from an '@actorIndependent' context}}
126+
syncGlobalActorFunc() /// expected-error{{global function 'syncGlobalActorFunc()' isolated to global actor 'SomeGlobalActor' can not be referenced from an '@actorIndependent' synchronous context}}
128127
_ = syncGlobalActorFunc // expected-error{{global function 'syncGlobalActorFunc()' isolated to global actor 'SomeGlobalActor' can not be referenced from an '@actorIndependent' context}}
129128

130129
// Global data is okay if it is immutable.
@@ -315,6 +314,10 @@ struct GenericGlobalActor<T> {
315314
static var shared: SomeActor { SomeActor() }
316315
}
317316

317+
@SomeGlobalActor func onions() {} // expected-note{{calls to global function 'onions()' from outside of its actor context are implicitly asynchronous}}
318+
319+
@MainActor func beets() { onions() } // expected-error{{global function 'onions()' isolated to global actor 'SomeGlobalActor' can not be referenced from different global actor 'MainActor' in a synchronous context}}
320+
318321
actor Crystal {
319322
// expected-note@+2 {{property declared here}}
320323
// expected-note@+1 2 {{mutation of this property is only permitted within the actor}}
@@ -449,7 +452,7 @@ var number: Int = 42 // expected-note {{var declared here}}
449452

450453
// expected-note@+1 {{add '@SomeGlobalActor' to make global function 'badNumberUser()' part of global actor 'SomeGlobalActor'}}
451454
func badNumberUser() {
452-
//expected-error@+1{{var 'number' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
455+
//expected-error@+1{{var 'number' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
453456
print("The protected number is: \(number)")
454457
}
455458

@@ -618,7 +621,7 @@ class SomeClassInActor {
618621

619622
extension SomeClassInActor.ID {
620623
func f(_ object: SomeClassInActor) { // expected-note{{add '@MainActor' to make instance method 'f' part of global actor 'MainActor'}}
621-
object.inActor() // expected-error{{instance method 'inActor()' isolated to global actor 'MainActor' can not be referenced from this context}}
624+
object.inActor() // expected-error{{instance method 'inActor()' isolated to global actor 'MainActor' can not be referenced from this synchronous context}}
622625
}
623626
}
624627

test/Concurrency/global_actor_from_ordinary_context.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func referenceAsyncGlobalActor() {
5757

5858
// expected-note@+1 {{add '@SomeGlobalActor' to make global function 'callGlobalActor()' part of global actor 'SomeGlobalActor'}} {{1-1=@SomeGlobalActor }}
5959
func callGlobalActor() {
60-
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
60+
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
6161
}
6262

6363
func fromClosure() {
@@ -67,36 +67,36 @@ func fromClosure() {
6767
x()
6868
}()
6969

70-
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
70+
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
7171
let _ = { syncGlobActorFn() }()
7272
}
7373

7474
class Taylor {
7575
init() {
76-
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
76+
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
7777

7878
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
7979
_ = syncGlobActorFn
8080
}
8181

8282
deinit {
83-
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
83+
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
8484

8585
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
8686
_ = syncGlobActorFn
8787
}
8888

8989
// expected-note@+1 2 {{add '@SomeGlobalActor' to make instance method 'method1()' part of global actor 'SomeGlobalActor'}} {{3-3=@SomeGlobalActor }}
9090
func method1() {
91-
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
91+
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
9292

9393
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
9494
_ = syncGlobActorFn
9595
}
9696

9797
// expected-note@+1 2 {{add '@SomeGlobalActor' to make instance method 'cannotBeHandler()' part of global actor 'SomeGlobalActor'}} {{3-3=@SomeGlobalActor }}
9898
func cannotBeHandler() -> Int {
99-
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
99+
syncGlobActorFn() // expected-error {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
100100

101101
// expected-error@+1 {{global function 'syncGlobActorFn()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
102102
_ = syncGlobActorFn

test/Concurrency/global_actor_inference.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ func bar() async {
231231

232232
// expected-note@+1 {{add '@SomeGlobalActor' to make global function 'barSync()' part of global actor 'SomeGlobalActor'}} {{1-1=@SomeGlobalActor }}
233233
func barSync() {
234-
foo() // expected-error {{global function 'foo()' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
234+
foo() // expected-error {{global function 'foo()' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
235235
}
236236

237237
// ----------------------------------------------------------------------
@@ -283,9 +283,9 @@ struct HasWrapperOnActor {
283283

284284
// expected-note@+1 3{{to make instance method 'testErrors()'}}
285285
func testErrors() {
286-
_ = synced // expected-error{{property 'synced' isolated to global actor 'MainActor' can not be referenced from this context}}
287-
_ = $synced // expected-error{{property '$synced' isolated to global actor 'SomeGlobalActor' can not be referenced from this context}}
288-
_ = _synced // expected-error{{property '_synced' isolated to global actor 'OtherGlobalActor' can not be referenced from this context}}
286+
_ = synced // expected-error{{property 'synced' isolated to global actor 'MainActor' can not be referenced from this synchronous context}}
287+
_ = $synced // expected-error{{property '$synced' isolated to global actor 'SomeGlobalActor' can not be referenced from this synchronous context}}
288+
_ = _synced // expected-error{{property '_synced' isolated to global actor 'OtherGlobalActor' can not be referenced from this synchronous context}}
289289
}
290290

291291
@MainActor mutating func testOnMain() {

0 commit comments

Comments
 (0)