Skip to content

Commit 74eb1a7

Browse files
committed
allow property/subscript access expressions for actors in typechecker
We now mark some DeclRefExpr and LookupExprs as implicitly async during typechecking, depending on whether they appear in a context that is only performing a read / get operation, and whether they are cross-actor operations. also resolves rdar://72403401 by improving the error messages (no more vague "'await' in async context" when its clearly a call!)
1 parent 5c29848 commit 74eb1a7

14 files changed

+613
-245
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+29-24
Original file line numberDiff line numberDiff line change
@@ -4190,8 +4190,12 @@ ERROR(async_call_without_await_in_autoclosure,none,
41904190
ERROR(async_call_without_await_in_async_let,none,
41914191
"call is 'async' in an 'async let' initializer that is not marked "
41924192
"with 'await'", ())
4193+
ERROR(async_prop_access_without_await,none,
4194+
"property access is 'async' but is not marked with 'await'", ())
4195+
ERROR(async_subscript_access_without_await,none,
4196+
"subscript access is 'async' but is not marked with 'await'", ())
41934197
WARNING(no_async_in_await,none,
4194-
"no calls to 'async' functions occur within 'await' expression", ())
4198+
"no 'async' operations occur within 'await' expression", ())
41954199
ERROR(async_call_in_illegal_context,none,
41964200
"'async' call cannot occur in "
41974201
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
@@ -4201,7 +4205,7 @@ ERROR(await_in_illegal_context,none,
42014205
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
42024206
(unsigned))
42034207
ERROR(async_in_nonasync_function,none,
4204-
"%select{'async'|'await'|'async let'}0 in "
4208+
"%select{'async'|'async' call|'await'|'async let'|'async' property access|'async' subscript access}0 in "
42054209
"%select{a function|an autoclosure}1 that does not support concurrency",
42064210
(unsigned, bool))
42074211
NOTE(note_add_async_to_function,none,
@@ -4279,13 +4283,13 @@ ERROR(actor_with_nonactor_superclass,none,
42794283
"actor class cannot inherit from non-actor class %0", (DeclName))
42804284

42814285
ERROR(actor_isolated_non_self_reference,none,
4282-
"actor-isolated %0 %1 can only be referenced "
4283-
"%select{inside the actor|on 'self'}2",
4284-
(DescriptiveDeclKind, DeclName, bool))
4286+
"actor-isolated %0 %1 can only be %select{referenced|mutated|used 'inout'}3 "
4287+
"%select{from inside the actor|on 'self'}2",
4288+
(DescriptiveDeclKind, DeclName, bool, unsigned))
42854289
ERROR(actor_isolated_self_independent_context,none,
4286-
"actor-isolated %0 %1 can not be referenced from an "
4290+
"actor-isolated %0 %1 can not be %select{referenced|mutated|used 'inout'}2 from an "
42874291
"'@actorIndependent' context",
4288-
(DescriptiveDeclKind, DeclName))
4292+
(DescriptiveDeclKind, DeclName, unsigned))
42894293
ERROR(actor_isolated_inout_state,none,
42904294
"actor-isolated %0 %1 cannot be passed 'inout' to"
42914295
"%select{| implicitly}2 'async' function call",
@@ -4298,34 +4302,34 @@ ERROR(actor_isolated_global_actor_context,none,
42984302
"actor %2",
42994303
(DescriptiveDeclKind, DeclName, Type))
43004304
ERROR(global_actor_from_instance_actor_context,none,
4301-
"%0 %1 isolated to global actor %2 can not be referenced from actor %3",
4302-
(DescriptiveDeclKind, DeclName, Type, DeclName))
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))
43034307
ERROR(global_actor_from_other_global_actor_context,none,
4304-
"%0 %1 isolated to global actor %2 can not be referenced from "
4305-
"different global actor %3",
4306-
(DescriptiveDeclKind, DeclName, Type, Type))
4308+
"%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))
43074311
ERROR(global_actor_from_nonactor_context,none,
4308-
"%0 %1 isolated to global actor %2 can not be referenced from "
4309-
"%select{this|an '@actorIndependent'}3 context",
4310-
(DescriptiveDeclKind, DeclName, Type, bool))
4312+
"%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))
43114315
ERROR(actor_isolated_partial_apply,none,
43124316
"actor-isolated %0 %1 can not be partially applied",
43134317
(DescriptiveDeclKind, DeclName))
43144318
ERROR(concurrent_access_local,none,
43154319
"use of local %0 %1 in concurrently-executing code",
43164320
(DescriptiveDeclKind, DeclName))
43174321
ERROR(actor_isolated_from_concurrent_closure,none,
4318-
"actor-isolated %0 %1 cannot be referenced from a concurrent closure",
4319-
(DescriptiveDeclKind, DeclName))
4322+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent closure",
4323+
(DescriptiveDeclKind, DeclName, unsigned))
43204324
ERROR(actor_isolated_from_concurrent_function,none,
4321-
"actor-isolated %0 %1 cannot be referenced from a concurrent function",
4322-
(DescriptiveDeclKind, DeclName))
4325+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent function",
4326+
(DescriptiveDeclKind, DeclName, unsigned))
43234327
ERROR(actor_isolated_from_async_let,none,
4324-
"actor-isolated %0 %1 cannot be referenced from 'async let' initializer",
4325-
(DescriptiveDeclKind, DeclName))
4328+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'async let' initializer",
4329+
(DescriptiveDeclKind, DeclName, unsigned))
43264330
ERROR(actor_isolated_from_escaping_closure,none,
4327-
"actor-isolated %0 %1 cannot be referenced from an '@escaping' closure",
4328-
(DescriptiveDeclKind, DeclName))
4331+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from an '@escaping' closure",
4332+
(DescriptiveDeclKind, DeclName, unsigned))
43294333
ERROR(local_function_executed_concurrently,none,
43304334
"concurrently-executed %0 %1 must be marked as '@concurrent'",
43314335
(DescriptiveDeclKind, DeclName))
@@ -4338,7 +4342,8 @@ NOTE(actor_isolated_sync_func,none,
43384342
"implicitly asynchronous",
43394343
(DescriptiveDeclKind, DeclName))
43404344
NOTE(actor_mutable_state,none,
4341-
"mutable state is only available within the actor instance", ())
4345+
"mutation of this %0 is only permitted within the actor",
4346+
(DescriptiveDeclKind))
43424347
WARNING(shared_mutable_state_access,none,
43434348
"reference to %0 %1 is not concurrency-safe because it involves "
43444349
"shared mutable state", (DescriptiveDeclKind, DeclName))

Diff for: include/swift/AST/Expr.h

+30-5
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ class alignas(8) Expr {
166166

167167
SWIFT_INLINE_BITFIELD_EMPTY(LiteralExpr, Expr);
168168
SWIFT_INLINE_BITFIELD_EMPTY(IdentityExpr, Expr);
169-
SWIFT_INLINE_BITFIELD(LookupExpr, Expr, 1,
170-
IsSuper : 1
169+
SWIFT_INLINE_BITFIELD(LookupExpr, Expr, 1+1,
170+
IsSuper : 1,
171+
IsImplicitlyAsync : 1
171172
);
172173
SWIFT_INLINE_BITFIELD_EMPTY(DynamicLookupExpr, LookupExpr);
173174

@@ -193,9 +194,10 @@ class alignas(8) Expr {
193194
LiteralCapacity : 32
194195
);
195196

196-
SWIFT_INLINE_BITFIELD(DeclRefExpr, Expr, 2+2,
197+
SWIFT_INLINE_BITFIELD(DeclRefExpr, Expr, 2+2+1,
197198
Semantics : 2, // an AccessSemantics
198-
FunctionRefKind : 2
199+
FunctionRefKind : 2,
200+
IsImplicitlyAsync : 1
199201
);
200202

201203
SWIFT_INLINE_BITFIELD(UnresolvedDeclRefExpr, Expr, 2+2,
@@ -1190,6 +1192,7 @@ class DeclRefExpr : public Expr {
11901192
Bits.DeclRefExpr.FunctionRefKind =
11911193
static_cast<unsigned>(Loc.isCompound() ? FunctionRefKind::Compound
11921194
: FunctionRefKind::Unapplied);
1195+
Bits.DeclRefExpr.IsImplicitlyAsync = false;
11931196
}
11941197

11951198
/// Retrieve the declaration to which this expression refers.
@@ -1203,6 +1206,16 @@ class DeclRefExpr : public Expr {
12031206
return (AccessSemantics) Bits.DeclRefExpr.Semantics;
12041207
}
12051208

1209+
/// Determine whether this reference needs to happen asynchronously, i.e.,
1210+
/// guarded by hop_to_executor
1211+
bool isImplicitlyAsync() const { return Bits.DeclRefExpr.IsImplicitlyAsync; }
1212+
1213+
/// Set whether this reference needs to happen asynchronously, i.e.,
1214+
/// guarded by hop_to_executor
1215+
void setImplicitlyAsync(bool isImplicitlyAsync) {
1216+
Bits.DeclRefExpr.IsImplicitlyAsync = isImplicitlyAsync;
1217+
}
1218+
12061219
/// Retrieve the concrete declaration reference.
12071220
ConcreteDeclRef getDeclRef() const {
12081221
return D;
@@ -1518,6 +1531,7 @@ class LookupExpr : public Expr {
15181531
bool Implicit)
15191532
: Expr(Kind, Implicit), Base(base), Member(member) {
15201533
Bits.LookupExpr.IsSuper = false;
1534+
Bits.LookupExpr.IsImplicitlyAsync = false;
15211535
assert(Base);
15221536
}
15231537

@@ -1547,6 +1561,16 @@ class LookupExpr : public Expr {
15471561
/// Set whether this reference refers to the superclass's property.
15481562
void setIsSuper(bool isSuper) { Bits.LookupExpr.IsSuper = isSuper; }
15491563

1564+
/// Determine whether this reference needs to happen asynchronously, i.e.,
1565+
/// guarded by hop_to_executor
1566+
bool isImplicitlyAsync() const { return Bits.LookupExpr.IsImplicitlyAsync; }
1567+
1568+
/// Set whether this reference needs to happen asynchronously, i.e.,
1569+
/// guarded by hop_to_executor
1570+
void setImplicitlyAsync(bool isImplicitlyAsync) {
1571+
Bits.LookupExpr.IsImplicitlyAsync = isImplicitlyAsync;
1572+
}
1573+
15501574
static bool classof(const Expr *E) {
15511575
return E->getKind() >= ExprKind::First_LookupExpr &&
15521576
E->getKind() <= ExprKind::Last_LookupExpr;
@@ -3118,7 +3142,7 @@ class DestructureTupleExpr final : public ImplicitConversionExpr,
31183142
class LoadExpr : public ImplicitConversionExpr {
31193143
public:
31203144
LoadExpr(Expr *subExpr, Type type)
3121-
: ImplicitConversionExpr(ExprKind::Load, subExpr, type) {}
3145+
: ImplicitConversionExpr(ExprKind::Load, subExpr, type) { }
31223146

31233147
static bool classof(const Expr *E) { return E->getKind() == ExprKind::Load; }
31243148
};
@@ -4398,6 +4422,7 @@ class ApplyExpr : public Expr {
43984422
}
43994423

44004424
/// Is this application _implicitly_ required to be an async call?
4425+
/// That is, does it need to be guarded by hop_to_executor.
44014426
/// Note that this is _not_ a check for whether the callee is async!
44024427
/// Only meaningful after complete type-checking.
44034428
///

0 commit comments

Comments
 (0)