Skip to content

Commit 7f11947

Browse files
hborlaHolly Borla
authored andcommitted
[Concurrency] Allow default initializer expressions for stored instance
properties to require actor isolation. Member initializer expressions are only used in a constructor with matching actor isolation. If the isolation prohibits the member initializer from being evaluated synchronously (or propagating required isolation through closure bodies), then the default value cannot be used and the member must be explicitly initialized in the constructor. Member initializer expressions are also used as default arguments for the memberwise initializer, and the same rules for default argument isolation apply.
1 parent 88b2332 commit 7f11947

12 files changed

+237
-24
lines changed

include/swift/AST/Decl.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1973,6 +1973,15 @@ class PatternBindingEntry {
19731973
SourceRange getOriginalInitRange() const;
19741974
void setInit(Expr *E);
19751975

1976+
/// Get the required actor isolation for evaluating the initializer
1977+
/// expression synchronously (if there is one).
1978+
///
1979+
/// If this pattern binding entry is for a stored instance property, the
1980+
/// initializer can only be used in an `init` that meets the required
1981+
/// isolation; otherwise, the property must be explicitly initialized in
1982+
/// the `init`.
1983+
ActorIsolation getInitializerIsolation() const;
1984+
19761985
/// Gets the text of the initializer expression, stripping out inactive
19771986
/// branches of any #ifs inside the expression.
19781987
StringRef getInitStringRepresentation(SmallVectorImpl<char> &scratch) const;
@@ -2226,6 +2235,10 @@ class PatternBindingDecl final : public Decl,
22262235
getMutablePatternList()[i].setOriginalInit(E);
22272236
}
22282237

2238+
ActorIsolation getInitializerIsolation(unsigned i) const {
2239+
return getPatternList()[i].getInitializerIsolation();
2240+
}
2241+
22292242
Pattern *getPattern(unsigned i) const {
22302243
return getPatternList()[i].getPattern();
22312244
}

include/swift/AST/TypeCheckRequests.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,23 +2935,27 @@ class DefaultArgumentTypeRequest
29352935
};
29362936

29372937
/// Compute the actor isolation needed to synchronously evaluate the
2938-
/// default argument for the given parameter.
2939-
class DefaultArgumentIsolation
2940-
: public SimpleRequest<DefaultArgumentIsolation,
2941-
ActorIsolation(ParamDecl *),
2938+
/// default initializer expression.
2939+
class DefaultInitializerIsolation
2940+
: public SimpleRequest<DefaultInitializerIsolation,
2941+
ActorIsolation(Initializer *, Expr *),
29422942
RequestFlags::Cached> {
29432943
public:
29442944
using SimpleRequest::SimpleRequest;
29452945

29462946
private:
29472947
friend SimpleRequest;
29482948

2949-
ActorIsolation evaluate(Evaluator &evaluator, ParamDecl *param) const;
2949+
ActorIsolation evaluate(Evaluator &evaluator,
2950+
Initializer *init,
2951+
Expr *initExpr) const;
29502952

29512953
public:
29522954
bool isCached() const { return true; }
29532955
};
29542956

2957+
void simple_display(llvm::raw_ostream &out, Initializer *init);
2958+
29552959
/// Computes the fully type-checked caller-side default argument within the
29562960
/// context of the call site that it will be inserted into.
29572961
class CallerSideDefaultArgExprRequest

include/swift/AST/TypeCheckerTypeIDZone.def

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +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, DefaultArgumentIsolation,
66-
ActorIsolation(ParamDecl *), Cached, NoLocationInfo)
65+
SWIFT_REQUEST(TypeChecker, DefaultInitializerIsolation,
66+
ActorIsolation(Initializer *, Expr *),
67+
Cached, NoLocationInfo)
6768
SWIFT_REQUEST(TypeChecker, DefaultArgumentInitContextRequest,
6869
Initializer *(ParamDecl *), SeparatelyCached, NoLocationInfo)
6970
SWIFT_REQUEST(TypeChecker, DefaultDefinitionTypeRequest,

lib/AST/Decl.cpp

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,6 +1976,20 @@ void PatternBindingEntry::setInit(Expr *E) {
19761976
PatternFlags::IsText);
19771977
}
19781978

1979+
ActorIsolation PatternBindingEntry::getInitializerIsolation() const {
1980+
if (!isInitialized())
1981+
return ActorIsolation::forUnspecified();
1982+
1983+
auto *dc = cast<Initializer>(getInitContext());
1984+
auto &ctx = dc->getASTContext();
1985+
auto *initExpr = getExecutableInit();
1986+
1987+
return evaluateOrDefault(
1988+
ctx.evaluator,
1989+
DefaultInitializerIsolation{dc, initExpr},
1990+
ActorIsolation::forNonisolated());
1991+
}
1992+
19791993
VarDecl *PatternBindingEntry::getAnchoringVarDecl() const {
19801994
SmallVector<VarDecl *, 8> variables;
19811995
getPattern()->collectVariables(variables);
@@ -8264,10 +8278,30 @@ Type ParamDecl::getTypeOfDefaultExpr() const {
82648278
}
82658279

82668280
ActorIsolation ParamDecl::getDefaultArgumentIsolation() const {
8281+
// If this parameter corresponds to a stored property for a
8282+
// memberwise initializer, the default argument is the default
8283+
// initializer expression.
8284+
auto *var = getStoredProperty();
8285+
if (var && !var->isInvalid()) {
8286+
// FIXME: Force computation of property wrapper initializers.
8287+
if (auto *wrapped = var->getOriginalWrappedProperty())
8288+
(void)wrapped->getPropertyWrapperInitializerInfo();
8289+
8290+
auto *pbd = var->getParentPatternBinding();
8291+
auto i = pbd->getPatternEntryIndexForVarDecl(var);
8292+
return var->getParentPatternBinding()->getInitializerIsolation(i);
8293+
}
8294+
8295+
if (!hasDefaultExpr())
8296+
return ActorIsolation::forUnspecified();
8297+
82678298
auto &ctx = getASTContext();
8299+
auto *dc = getDefaultArgumentInitContext();
8300+
auto *initExpr = getTypeCheckedDefaultExpr();
8301+
82688302
return evaluateOrDefault(
82698303
ctx.evaluator,
8270-
DefaultArgumentIsolation{const_cast<ParamDecl *>(this)},
8304+
DefaultInitializerIsolation{dc, initExpr},
82718305
ActorIsolation::forNonisolated());
82728306
}
82738307

@@ -10453,8 +10487,25 @@ ActorIsolation swift::getActorIsolationOfContext(
1045310487
if (auto *vd = dyn_cast_or_null<ValueDecl>(dcToUse->getAsDecl()))
1045410488
return getActorIsolation(vd);
1045510489

10456-
if (auto *var = dcToUse->getNonLocalVarDecl())
10490+
// In the context of the initializing or default-value expression of a
10491+
// stored property, the isolation varies between instance and type members:
10492+
// - For a static stored property, the isolation matches the VarDecl.
10493+
// Static properties are initialized upon first use, so the isolation
10494+
// of the initializer must match the isolation required to access the
10495+
// property.
10496+
// - For a field of a nominal type, the expression can require a specific
10497+
// actor isolation. That default expression may only be used from inits
10498+
// that meet the required isolation.
10499+
if (auto *var = dcToUse->getNonLocalVarDecl()) {
10500+
auto &ctx = dc->getASTContext();
10501+
if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultArguments) &&
10502+
var->isInstanceMember() &&
10503+
!var->getAttrs().hasAttribute<LazyAttr>()) {
10504+
return ActorIsolation::forNonisolated();
10505+
}
10506+
1045710507
return getActorIsolation(var);
10508+
}
1045810509

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

lib/AST/TypeCheckRequests.cpp

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

1305+
//----------------------------------------------------------------------------//
1306+
// DefaultInitializerIsolation computation.
1307+
//----------------------------------------------------------------------------//
1308+
1309+
void swift::simple_display(llvm::raw_ostream &out, Initializer *init) {
1310+
switch (init->getInitializerKind()) {
1311+
case InitializerKind::PatternBinding:
1312+
out << "pattern binding initializer";
1313+
break;
1314+
case InitializerKind::DefaultArgument:
1315+
out << "default argument initializer";
1316+
break;
1317+
case InitializerKind::PropertyWrapper:
1318+
out << "property wrapper initializer";
1319+
break;
1320+
}
1321+
}
1322+
13051323
//----------------------------------------------------------------------------//
13061324
// CallerSideDefaultArgExprRequest computation.
13071325
//----------------------------------------------------------------------------//

lib/SILGen/SILGenConstructor.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1542,6 +1542,26 @@ void SILGenFunction::emitMemberInitializer(DeclContext *dc, VarDecl *selfDecl,
15421542
if (!init)
15431543
continue;
15441544

1545+
// Member initializer expressions are only used in a constructor with
1546+
// matching actor isolation. If the isolation prohibits the member
1547+
// initializer from being evaluated synchronously (or propagating required
1548+
// isolation through closure bodies), then the default value cannot be used
1549+
// and the member must be explicitly initialized in the constructor.
1550+
auto requiredIsolation = field->getInitializerIsolation(i);
1551+
auto contextIsolation = getActorIsolationOfContext(dc);
1552+
switch (requiredIsolation) {
1553+
// 'nonisolated' expressions can be evaluated from anywhere
1554+
case ActorIsolation::Unspecified:
1555+
case ActorIsolation::Nonisolated:
1556+
break;
1557+
1558+
case ActorIsolation::GlobalActor:
1559+
case ActorIsolation::GlobalActorUnsafe:
1560+
case ActorIsolation::ActorInstance:
1561+
if (requiredIsolation != contextIsolation)
1562+
continue;
1563+
}
1564+
15451565
auto *varPattern = field->getPattern(i);
15461566

15471567
// Cleanup after this initialization.

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3582,11 +3582,6 @@ void swift::checkFunctionActorIsolation(AbstractFunctionDecl *decl) {
35823582
}
35833583
}
35843584

3585-
void swift::checkInitializerActorIsolation(Initializer *init, Expr *expr) {
3586-
ActorIsolationChecker checker(init);
3587-
expr->walk(checker);
3588-
}
3589-
35903585
ActorIsolation
35913586
swift::computeRequiredIsolation(Initializer *init, Expr *expr) {
35923587
ActorIsolationChecker checker(init);

lib/Sema/TypeCheckConcurrency.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ void addAsyncNotes(AbstractFunctionDecl const* func);
5656
/// Check actor isolation rules.
5757
void checkTopLevelActorIsolation(TopLevelCodeDecl *decl);
5858
void checkFunctionActorIsolation(AbstractFunctionDecl *decl);
59-
void checkInitializerActorIsolation(Initializer *init, Expr *expr);
6059
void checkEnumElementActorIsolation(EnumElementDecl *element, Expr *expr);
6160
void checkPropertyWrapperActorIsolation(VarDecl *wrappedVar, Expr *expr);
6261

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,14 +1157,13 @@ Expr *DefaultArgumentExprRequest::evaluate(Evaluator &evaluator,
11571157
}
11581158

11591159
ActorIsolation
1160-
DefaultArgumentIsolation::evaluate(Evaluator &evaluator,
1161-
ParamDecl *param) const {
1162-
if (!param->hasDefaultExpr())
1160+
DefaultInitializerIsolation::evaluate(Evaluator &evaluator,
1161+
Initializer *init,
1162+
Expr *initExpr) const {
1163+
if (!init || !initExpr)
11631164
return ActorIsolation::forUnspecified();
11641165

1165-
auto *dc = param->getDefaultArgumentInitContext();
1166-
auto *initExpr = param->getTypeCheckedDefaultExpr();
1167-
return computeRequiredIsolation(dc, initExpr);
1166+
return computeRequiredIsolation(init, initExpr);
11681167
}
11691168

11701169
Type DefaultArgumentTypeRequest::evaluate(Evaluator &evaluator,
@@ -2477,7 +2476,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
24772476
PBD->getInitContext(i));
24782477
if (initContext) {
24792478
TypeChecker::contextualizeInitializer(initContext, init);
2480-
checkInitializerActorIsolation(initContext, init);
2479+
(void)PBD->getInitializerIsolation(i);
24812480
TypeChecker::checkInitializerEffects(initContext, init);
24822481
}
24832482
}

lib/Sema/TypeCheckStorage.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,7 +3226,7 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
32263226
// synthesize a computed property for '$foo'.
32273227
Expr *projectedValueInit = nullptr;
32283228
if (auto *projection = var->getPropertyWrapperProjectionVar()) {
3229-
createPBD(projection);
3229+
auto *pbd = createPBD(projection);
32303230

32313231
if (var->hasExternalPropertyWrapper()) {
32323232
// Projected-value initialization is currently only supported for parameters.
@@ -3240,7 +3240,7 @@ PropertyWrapperInitializerInfoRequest::evaluate(Evaluator &evaluator,
32403240
// Check initializer effects.
32413241
auto *initContext = new (ctx) PropertyWrapperInitializer(
32423242
dc, param, PropertyWrapperInitializer::Kind::ProjectedValue);
3243-
checkInitializerActorIsolation(initContext, projectedValueInit);
3243+
(void)pbd->getInitializerIsolation(0);
32443244
TypeChecker::checkInitializerEffects(initContext, projectedValueInit);
32453245
}
32463246
}

0 commit comments

Comments
 (0)