Skip to content

Commit 931c47d

Browse files
authored
Merge pull request #35965 from kavon/actor-effectful-properties
2 parents 7a13126 + de0d998 commit 931c47d

22 files changed

+1473
-346
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 29 additions & 24 deletions
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))

include/swift/AST/Expr.h

Lines changed: 30 additions & 5 deletions
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
///

lib/SILGen/LValue.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,16 @@ class PhysicalPathComponent : public PathComponent {
209209
virtual void _anchor() override;
210210

211211
protected:
212-
PhysicalPathComponent(LValueTypeData typeData, KindTy Kind)
213-
: PathComponent(typeData, Kind) {
212+
Optional<ActorIsolation> ActorIso;
213+
PhysicalPathComponent(LValueTypeData typeData, KindTy Kind,
214+
Optional<ActorIsolation> actorIso = None)
215+
: PathComponent(typeData, Kind), ActorIso(actorIso) {
214216
assert(isPhysical() && "PhysicalPathComponent Kind isn't physical");
215217
}
218+
219+
public:
220+
// Obtains the actor-isolation required for any loads of this component.
221+
Optional<ActorIsolation> getActorIsolation() const { return ActorIso; }
216222
};
217223

218224
inline PhysicalPathComponent &PathComponent::asPhysical() {
@@ -421,12 +427,19 @@ class LValue {
421427
Path.emplace_back(new T(std::forward<As>(args)...));
422428
}
423429

430+
// NOTE: Optional<ActorIsolation> inside of LValues
431+
// Some path components carry an ActorIsolation value, which is an indicator
432+
// that the access to that component must be performed by switching to the
433+
// given actor's isolation domain. If the indicator is not present, that
434+
// only means that a switch does not need to be emitted during the access.
435+
424436
void addNonMemberVarComponent(SILGenFunction &SGF, SILLocation loc,
425437
VarDecl *var, SubstitutionMap subs,
426438
LValueOptions options,
427439
SGFAccessKind accessKind,
428440
AccessStrategy strategy,
429-
CanType formalRValueType);
441+
CanType formalRValueType,
442+
Optional<ActorIsolation> actorIso = None);
430443

431444
/// Add a member component to the access path of this lvalue.
432445
void addMemberComponent(SILGenFunction &SGF, SILLocation loc,
@@ -448,7 +461,8 @@ class LValue {
448461
SGFAccessKind accessKind,
449462
AccessStrategy accessStrategy,
450463
CanType formalRValueType,
451-
bool isOnSelf = false);
464+
bool isOnSelf = false,
465+
Optional<ActorIsolation> actorIso = None);
452466

453467
void addMemberSubscriptComponent(SILGenFunction &SGF, SILLocation loc,
454468
SubscriptDecl *subscript,
@@ -460,7 +474,8 @@ class LValue {
460474
CanType formalRValueType,
461475
PreparedArguments &&indices,
462476
Expr *indexExprForDiagnostics,
463-
bool isOnSelfParameter = false);
477+
bool isOnSelfParameter = false,
478+
Optional<ActorIsolation> actorIso = None);
464479

465480
/// Add a subst-to-orig reabstraction component. That is, given
466481
/// that this l-value trafficks in values following the substituted

lib/SILGen/SILGenApply.cpp

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4285,30 +4285,6 @@ bool SILGenModule::isNonMutatingSelfIndirect(SILDeclRef methodRef) {
42854285
return self.isFormalIndirect();
42864286
}
42874287

4288-
Optional<SILValue> SILGenFunction::emitLoadActorExecutorForCallee(
4289-
ValueDecl *calleeVD,
4290-
ArrayRef<ManagedValue> args) {
4291-
if (auto *funcDecl = dyn_cast_or_null<AbstractFunctionDecl>(calleeVD)) {
4292-
auto actorIso = getActorIsolation(funcDecl);
4293-
switch (actorIso.getKind()) {
4294-
case ActorIsolation::Unspecified:
4295-
case ActorIsolation::Independent:
4296-
case ActorIsolation::IndependentUnsafe:
4297-
break;
4298-
4299-
case ActorIsolation::ActorInstance: {
4300-
assert(args.size() > 0 && "no self argument for actor-instance call?");
4301-
auto calleeSelf = args.back();
4302-
return calleeSelf.borrow(*this, F.getLocation()).getValue();
4303-
}
4304-
4305-
case ActorIsolation::GlobalActor:
4306-
case ActorIsolation::GlobalActorUnsafe:
4307-
return emitLoadGlobalActorExecutor(actorIso.getGlobalActor());
4308-
}
4309-
}
4310-
return None;
4311-
}
43124288

43134289
//===----------------------------------------------------------------------===//
43144290
// Top Level Entrypoints
@@ -4418,10 +4394,16 @@ RValue SILGenFunction::emitApply(ResultPlanPtr &&resultPlan,
44184394
assert(F.isAsync() && "cannot hop_to_executor in a non-async func!");
44194395

44204396
auto calleeVD = implicitlyAsyncApply.getValue();
4421-
auto maybeExecutor = emitLoadActorExecutorForCallee(calleeVD, args);
4397+
if (auto *funcDecl = dyn_cast_or_null<AbstractFunctionDecl>(calleeVD)) {
4398+
Optional<ManagedValue> actorSelf;
44224399

4423-
assert(maybeExecutor.hasValue());
4424-
B.createHopToExecutor(loc, maybeExecutor.getValue());
4400+
if (args.size() > 0)
4401+
actorSelf = args.back();
4402+
4403+
auto didHop = emitHopToTargetActor(loc, getActorIsolation(funcDecl),
4404+
actorSelf);
4405+
assert(didHop);
4406+
}
44254407
}
44264408

44274409
SILValue rawDirectResult;

lib/SILGen/SILGenExpr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "Callee.h"
1616
#include "Condition.h"
1717
#include "Conversion.h"
18-
#include "ExitableFullExpr.h"
1918
#include "Initialization.h"
2019
#include "LValue.h"
2120
#include "RValue.h"
@@ -2199,6 +2198,7 @@ RValue RValueEmitter::visitMemberRefExpr(MemberRefExpr *e,
21992198

22002199
RValue RValueEmitter::visitDynamicMemberRefExpr(DynamicMemberRefExpr *E,
22012200
SGFContext C) {
2201+
assert(!E->isImplicitlyAsync() && "actors do not have @objc members");
22022202
return SGF.emitDynamicMemberRefExpr(E, C);
22032203
}
22042204

@@ -2220,6 +2220,7 @@ RValue RValueEmitter::visitSubscriptExpr(SubscriptExpr *E, SGFContext C) {
22202220

22212221
RValue RValueEmitter::visitDynamicSubscriptExpr(
22222222
DynamicSubscriptExpr *E, SGFContext C) {
2223+
assert(!E->isImplicitlyAsync() && "actors do not have @objc members");
22232224
return SGF.emitDynamicSubscriptExpr(E, C);
22242225
}
22252226

lib/SILGen/SILGenFunction.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -857,12 +857,13 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
857857
// Concurrency
858858
//===--------------------------------------------------------------------===//
859859

860-
/// Generates code to obtain the callee function's executor, if the function
861-
/// is actor-isolated.
860+
/// Generates code to obtain the executor for the given actor isolation,
861+
/// as-needed, and emits a \c hop_to_executor to that executor.
862862
///
863-
/// \returns a SILValue representing the executor, if an executor exists.
864-
Optional<SILValue> emitLoadActorExecutorForCallee(ValueDecl *calleeVD,
865-
ArrayRef<ManagedValue> args);
863+
/// \returns a non-null pointer if a \c hop_to_executor was emitted.
864+
HopToExecutorInst* emitHopToTargetActor(SILLocation loc,
865+
Optional<ActorIsolation> actorIso,
866+
Optional<ManagedValue> actorSelf);
866867

867868
/// Generates code to obtain the executor given the actor's decl.
868869
/// \returns a SILValue representing the executor.

0 commit comments

Comments
 (0)