Skip to content

Commit 533bcda

Browse files
authored
Merge pull request #69149 from hborla/5.10-isolated-initializer-expressions
[5.10][Concurrency] Allow default arguments to require actor isolation.
2 parents 0ad87ab + 931d16c commit 533bcda

22 files changed

+664
-14
lines changed

include/swift/AST/Decl.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2250,7 +2250,9 @@ class PatternBindingDecl final : public Decl,
22502250
void setInitializerSubsumed(unsigned i) {
22512251
getMutablePatternList()[i].setInitializerSubsumed();
22522252
}
2253-
2253+
2254+
ActorIsolation getInitializerIsolation(unsigned i) const;
2255+
22542256
/// Does this binding declare something that requires storage?
22552257
bool hasStorage() const;
22562258

@@ -5935,6 +5937,19 @@ class VarDecl : public AbstractStorageDecl {
59355937
return getParentExecutableInitializer() != nullptr;
59365938
}
59375939

5940+
/// Get the required actor isolation for evaluating the initializer
5941+
/// expression synchronously (if there is one).
5942+
///
5943+
/// If this VarDecl is a stored instance property, the initializer
5944+
/// can only be used in an `init` that meets the required isolation.
5945+
/// Otherwise, the property must be explicitly initialized in the `init`.
5946+
///
5947+
/// If this is a ParamDecl, the initializer isolation is required at
5948+
/// the call-site in order to use the default argument for this parameter.
5949+
/// If the required isolation is not met, an argument must be written
5950+
/// explicitly at the call-site.
5951+
ActorIsolation getInitializerIsolation() const;
5952+
59385953
// Return whether this VarDecl has an initial value, either by checking
59395954
// if it has an initializer in its parent pattern binding or if it has
59405955
// the @_hasInitialValue attribute.

include/swift/AST/DiagnosticsSema.def

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5203,6 +5203,13 @@ ERROR(distributed_actor_isolated_non_self_reference,none,
52035203
"distributed actor-isolated %kind0 can not be accessed from a "
52045204
"non-isolated context",
52055205
(const ValueDecl *))
5206+
ERROR(isolated_default_argument,none,
5207+
"%0 default argument cannot be synchronously evaluated from a "
5208+
"%1 context",
5209+
(ActorIsolation, ActorIsolation))
5210+
ERROR(conflicting_default_argument_isolation,none,
5211+
"default argument cannot be both %0 and %1",
5212+
(ActorIsolation, ActorIsolation))
52065213
ERROR(distributed_actor_needs_explicit_distributed_import,none,
52075214
"'Distributed' module not imported, required for 'distributed actor'",
52085215
())

include/swift/AST/Expr.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4538,6 +4538,11 @@ class DefaultArgumentExpr final : public Expr {
45384538
/// expression within the context of the call site.
45394539
Expr *getCallerSideDefaultExpr() const;
45404540

4541+
/// Get the required actor isolation for evaluating this default argument
4542+
/// synchronously. If the caller does not meet the required isolation, the
4543+
/// argument must be written explicitly at the call-site.
4544+
ActorIsolation getRequiredIsolation() const;
4545+
45414546
static bool classof(const Expr *E) {
45424547
return E->getKind() == ExprKind::DefaultArgument;
45434548
}

include/swift/AST/TypeCheckRequests.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2911,6 +2911,27 @@ class DefaultArgumentTypeRequest
29112911
void cacheResult(Type type) const;
29122912
};
29132913

2914+
/// Compute the actor isolation needed to synchronously evaluate the
2915+
/// default initializer expression.
2916+
class DefaultInitializerIsolation
2917+
: public SimpleRequest<DefaultInitializerIsolation,
2918+
ActorIsolation(VarDecl *),
2919+
RequestFlags::Cached> {
2920+
public:
2921+
using SimpleRequest::SimpleRequest;
2922+
2923+
private:
2924+
friend SimpleRequest;
2925+
2926+
ActorIsolation evaluate(Evaluator &evaluator,
2927+
VarDecl *) const;
2928+
2929+
public:
2930+
bool isCached() const { return true; }
2931+
};
2932+
2933+
void simple_display(llvm::raw_ostream &out, Initializer *init);
2934+
29142935
/// Computes the fully type-checked caller-side default argument within the
29152936
/// context of the call site that it will be inserted into.
29162937
class CallerSideDefaultArgExprRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ SWIFT_REQUEST(TypeChecker, DefaultArgumentExprRequest,
6262
Expr *(ParamDecl *), SeparatelyCached, NoLocationInfo)
6363
SWIFT_REQUEST(TypeChecker, DefaultArgumentTypeRequest,
6464
Type(ParamDecl *), SeparatelyCached, NoLocationInfo)
65+
SWIFT_REQUEST(TypeChecker, DefaultInitializerIsolation,
66+
ActorIsolation(VarDecl *),
67+
Cached, NoLocationInfo)
6568
SWIFT_REQUEST(TypeChecker, DefaultArgumentInitContextRequest,
6669
Initializer *(ParamDecl *), SeparatelyCached, NoLocationInfo)
6770
SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,

include/swift/Basic/Features.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ EXPERIMENTAL_FEATURE(SendNonSendable, false)
222222
/// Within strict concurrency, narrow global variable isolation requirements.
223223
EXPERIMENTAL_FEATURE(GlobalConcurrency, false)
224224

225+
/// Allow default values to require isolation at the call-site.
226+
EXPERIMENTAL_FEATURE(IsolatedDefaultValues, false)
227+
225228
/// Enable extended callbacks (with additional parameters) to be used when the
226229
/// "playground transform" is enabled.
227230
EXPERIMENTAL_FEATURE(PlaygroundExtendedCallbacks, true)

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,6 +3502,10 @@ static bool usesFeatureSendNonSendable(Decl *decl) {
35023502

35033503
static bool usesFeatureGlobalConcurrency(Decl *decl) { return false; }
35043504

3505+
static bool usesFeatureIsolatedDefaultValues(Decl *decl) {
3506+
return false;
3507+
}
3508+
35053509
static bool usesFeaturePlaygroundExtendedCallbacks(Decl *decl) {
35063510
return false;
35073511
}

lib/AST/Decl.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2065,6 +2065,14 @@ bool PatternBindingDecl::isAsyncLet() const {
20652065
return false;
20662066
}
20672067

2068+
ActorIsolation
2069+
PatternBindingDecl::getInitializerIsolation(unsigned i) const {
2070+
auto *var = getPatternList()[i].getAnchoringVarDecl();
2071+
if (!var)
2072+
return ActorIsolation::forUnspecified();
2073+
2074+
return var->getInitializerIsolation();
2075+
}
20682076

20692077
bool PatternBindingDecl::hasStorage() const {
20702078
// Walk the pattern, to check to see if any of the VarDecls included in it
@@ -7046,6 +7054,14 @@ Expr *VarDecl::getParentExecutableInitializer() const {
70467054
return nullptr;
70477055
}
70487056

7057+
ActorIsolation VarDecl::getInitializerIsolation() const {
7058+
auto *mutableThis = const_cast<VarDecl *>(this);
7059+
return evaluateOrDefault(
7060+
getASTContext().evaluator,
7061+
DefaultInitializerIsolation{mutableThis},
7062+
ActorIsolation::forUnspecified());
7063+
}
7064+
70497065
SourceRange VarDecl::getSourceRange() const {
70507066
if (auto Param = dyn_cast<ParamDecl>(this))
70517067
return Param->getSourceRange();
@@ -10266,8 +10282,25 @@ ActorIsolation swift::getActorIsolationOfContext(
1026610282
if (auto *vd = dyn_cast_or_null<ValueDecl>(dcToUse->getAsDecl()))
1026710283
return getActorIsolation(vd);
1026810284

10269-
if (auto *var = dcToUse->getNonLocalVarDecl())
10285+
// In the context of the initializing or default-value expression of a
10286+
// stored property, the isolation varies between instance and type members:
10287+
// - For a static stored property, the isolation matches the VarDecl.
10288+
// Static properties are initialized upon first use, so the isolation
10289+
// of the initializer must match the isolation required to access the
10290+
// property.
10291+
// - For a field of a nominal type, the expression can require a specific
10292+
// actor isolation. That default expression may only be used from inits
10293+
// that meet the required isolation.
10294+
if (auto *var = dcToUse->getNonLocalVarDecl()) {
10295+
auto &ctx = dc->getASTContext();
10296+
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues) &&
10297+
var->isInstanceMember() &&
10298+
!var->getAttrs().hasAttribute<LazyAttr>()) {
10299+
return ActorIsolation::forNonisolated();
10300+
}
10301+
1027010302
return getActorIsolation(var);
10303+
}
1027110304

1027210305
if (auto *closure = dyn_cast<AbstractClosureExpr>(dcToUse)) {
1027310306
return getClosureActorIsolation(closure);

lib/AST/Expr.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,6 +1601,11 @@ Expr *DefaultArgumentExpr::getCallerSideDefaultExpr() const {
16011601
new (ctx) ErrorExpr(getSourceRange(), getType()));
16021602
}
16031603

1604+
ActorIsolation
1605+
DefaultArgumentExpr::getRequiredIsolation() const {
1606+
return getParamDecl()->getInitializerIsolation();
1607+
}
1608+
16041609
ValueDecl *ApplyExpr::getCalledValue(bool skipFunctionConversions) const {
16051610
return ::getCalledValue(Fn, skipFunctionConversions);
16061611
}

lib/AST/TypeCheckRequests.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,6 +1270,24 @@ void DefaultArgumentTypeRequest::cacheResult(Type type) const {
12701270
param->setDefaultExprType(type);
12711271
}
12721272

1273+
//----------------------------------------------------------------------------//
1274+
// DefaultInitializerIsolation computation.
1275+
//----------------------------------------------------------------------------//
1276+
1277+
void swift::simple_display(llvm::raw_ostream &out, Initializer *init) {
1278+
switch (init->getInitializerKind()) {
1279+
case InitializerKind::PatternBinding:
1280+
out << "pattern binding initializer";
1281+
break;
1282+
case InitializerKind::DefaultArgument:
1283+
out << "default argument initializer";
1284+
break;
1285+
case InitializerKind::PropertyWrapper:
1286+
out << "property wrapper initializer";
1287+
break;
1288+
}
1289+
}
1290+
12731291
//----------------------------------------------------------------------------//
12741292
// CallerSideDefaultArgExprRequest computation.
12751293
//----------------------------------------------------------------------------//

lib/SILGen/SILGenConstructor.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,27 @@ void SILGenFunction::emitMemberInitializer(DeclContext *dc, VarDecl *selfDecl,
15261526
if (!init)
15271527
continue;
15281528

1529+
// Member initializer expressions are only used in a constructor with
1530+
// matching actor isolation. If the isolation prohibits the member
1531+
// initializer from being evaluated synchronously (or propagating required
1532+
// isolation through closure bodies), then the default value cannot be used
1533+
// and the member must be explicitly initialized in the constructor.
1534+
auto *var = field->getAnchoringVarDecl(i);
1535+
auto requiredIsolation = var->getInitializerIsolation();
1536+
auto contextIsolation = getActorIsolationOfContext(dc);
1537+
switch (requiredIsolation) {
1538+
// 'nonisolated' expressions can be evaluated from anywhere
1539+
case ActorIsolation::Unspecified:
1540+
case ActorIsolation::Nonisolated:
1541+
break;
1542+
1543+
case ActorIsolation::GlobalActor:
1544+
case ActorIsolation::GlobalActorUnsafe:
1545+
case ActorIsolation::ActorInstance:
1546+
if (requiredIsolation != contextIsolation)
1547+
continue;
1548+
}
1549+
15291550
auto *varPattern = field->getPattern(i);
15301551

15311552
// Cleanup after this initialization.

0 commit comments

Comments
 (0)