Skip to content

Commit f473bad

Browse files
committed
[Macros] "Subsume" the initializer when an accessor macros adds non-observers
When an accessor macro adds a non-observing accessor to a property, it subsumes the initializer. We had previously modeled this as removing the initializer, but doing so means that the initializer could not be used for type inference and was lost in the AST. Explicitly mark the initializer as "subsumed" here, and be more careful when querying the initializer to distinguish between "the initializer that was written" and "the initializer that will execute" in more places. This distinction already existed at the pattern-binding level, but not at the variable-declaration level. This is the proper fix for the circular reference issue described in rdar://108565923 (test case in the prior commit).
1 parent 7813c8c commit f473bad

File tree

10 files changed

+46
-17
lines changed

10 files changed

+46
-17
lines changed

include/swift/AST/Decl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5742,6 +5742,16 @@ class VarDecl : public AbstractStorageDecl {
57425742
return false;
57435743
}
57445744

5745+
/// Return the initializer that will initializer this VarDecl at runtime.
5746+
/// This is equivalent to `getParentInitializer()`, but returns `null` if the
5747+
/// initializer itself was subsumed, e.g., by a macro or property wrapper.
5748+
Expr *getParentExecutableInitializer() const;
5749+
5750+
/// Whether this variable has an initializer that will be code-generated.
5751+
bool isParentExecutabledInitialized() const {
5752+
return getParentExecutableInitializer() != nullptr;
5753+
}
5754+
57455755
// Return whether this VarDecl has an initial value, either by checking
57465756
// if it has an initializer in its parent pattern binding or if it has
57475757
// the @_hasInitialValue attribute.

lib/AST/Decl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6644,6 +6644,15 @@ bool VarDecl::isLazilyInitializedGlobal() const {
66446644
return !isTopLevelGlobal();
66456645
}
66466646

6647+
Expr *VarDecl::getParentExecutableInitializer() const {
6648+
if (auto *PBD = getParentPatternBinding()) {
6649+
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
6650+
return PBD->getExecutableInit(i);
6651+
}
6652+
6653+
return nullptr;
6654+
}
6655+
66476656
SourceRange VarDecl::getSourceRange() const {
66486657
if (auto Param = dyn_cast<ParamDecl>(this))
66496658
return Param->getSourceRange();

lib/SILGen/SILGenConstructor.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
401401
++elti;
402402
} else {
403403
assert(field->getType()->getReferenceStorageReferent()->isEqual(
404-
field->getParentInitializer()->getType()) &&
404+
field->getParentExecutableInitializer()->getType()) &&
405405
"Initialization of field with mismatched type!");
406406

407407
// Cleanup after this initialization.
@@ -422,7 +422,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
422422
}
423423
}
424424

425-
SGF.emitExprInto(field->getParentInitializer(), init.get());
425+
SGF.emitExprInto(field->getParentExecutableInitializer(), init.get());
426426
}
427427
if (SGF.getOptions().EnableImportPtrauthFieldFunctionPointers &&
428428
field->getPointerAuthQualifier().isPresent()) {
@@ -454,8 +454,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
454454
++elti;
455455
} else {
456456
// Otherwise, use its initializer.
457-
assert(field->isParentInitialized());
458-
Expr *init = field->getParentInitializer();
457+
assert(field->isParentExecutabledInitialized());
458+
Expr *init = field->getParentExecutableInitializer();
459459

460460
// If this is a property wrapper backing storage var that isn't
461461
// memberwise initialized, use the original wrapped value if it exists.

lib/SILGen/SILGenDecl.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,8 @@ class LetValueInitialization : public Initialization {
640640

641641
assert(!isa<ParamDecl>(vd)
642642
&& "should not bind function params on this path");
643-
if (vd->getParentPatternBinding() && !vd->getParentInitializer()) {
643+
if (vd->getParentPatternBinding() &&
644+
!vd->getParentExecutableInitializer()) {
644645
// If this is a let-value without an initializer, then we need a temporary
645646
// buffer. DI will make sure it is only assigned to once.
646647
needsTemporaryBuffer = true;
@@ -1427,8 +1428,8 @@ SILGenFunction::emitInitializationForVarDecl(VarDecl *vd, bool forceImmutable,
14271428
// If the variable has no initial value, emit a mark_uninitialized instruction
14281429
// so that DI tracks and enforces validity of it.
14291430
bool isUninitialized =
1430-
vd->getParentPatternBinding() && !vd->getParentInitializer();
1431-
1431+
vd->getParentPatternBinding() && !vd->getParentExecutableInitializer();
1432+
14321433
// If this is a global variable, initialize it without allocations or
14331434
// cleanups.
14341435
InitializationPtr Result;

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,7 +1358,7 @@ void LifetimeChecker::handleStoreUse(unsigned UseID) {
13581358
StringRef(PropertyName));
13591359

13601360
if (auto *Var = dyn_cast<VarDecl>(VD)) {
1361-
if (Var->getParentInitializer())
1361+
if (Var->getParentExecutableInitializer())
13621362
diagnose(Module, SILLocation(VD),
13631363
diag::initial_value_provided_in_let_decl);
13641364
Var->emitLetToVarNoteIfSimple(nullptr);

lib/Sema/DebuggerTestingTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class DebuggerTestingTransform : public ASTWalker {
184184

185185
// Don't capture variables which aren't default-initialized.
186186
if (auto *VD = dyn_cast<VarDecl>(DstDecl))
187-
if (!VD->isParentInitialized() &&
187+
if (!VD->isParentExecutabledInitialized() &&
188188
!(isa<ParamDecl>(VD) &&
189189
cast<ParamDecl>(VD)->isInOut()))
190190
return Action::Continue(OriginalExpr);

lib/Sema/PCMacro.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,7 @@ class Instrumenter : InstrumenterBase {
468468
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
469469
// FIXME: Should iterate all var decls
470470
if (VarDecl *VD = PBD->getSingleVar()) {
471-
if (VD->getParentInitializer()) {
471+
if (VD->getParentExecutableInitializer()) {
472472

473473
SourceRange SR = PBD->getSourceRange();
474474
if (!SR.isValid()) {

lib/Sema/PlaygroundTransform.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ class Instrumenter : InstrumenterBase {
581581
if (auto *PBD = dyn_cast<PatternBindingDecl>(D)) {
582582
if (!PBD->isAsyncLet()) {
583583
if (VarDecl *VD = PBD->getSingleVar()) {
584-
if (VD->getParentInitializer()) {
584+
if (VD->getParentExecutableInitializer()) {
585585
Added<Stmt *> Log = logVarDecl(VD);
586586
if (*Log) {
587587
Elements.insert(Elements.begin() + (EI + 1), *Log);

lib/Sema/TypeCheckMacros.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,12 +1332,12 @@ Optional<unsigned> swift::expandAccessors(
13321332
if (accessor->isObservingAccessor())
13331333
continue;
13341334

1335-
// If any non-observing accessor was added, remove the initializer if
1336-
// there is one.
1335+
// If any non-observing accessor was added, mark the initializer as
1336+
// subsumed.
13371337
if (auto var = dyn_cast<VarDecl>(storage)) {
13381338
if (auto binding = var->getParentPatternBinding()) {
13391339
unsigned index = binding->getPatternEntryIndexForVarDecl(var);
1340-
binding->setInit(index, nullptr);
1340+
binding->setInitializerSubsumed(index);
13411341
break;
13421342
}
13431343
}

lib/Sema/TypeCheckStorage.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3292,10 +3292,10 @@ static void finishNSManagedImplInfo(VarDecl *var,
32923292
if (info.isSimpleStored()) {
32933293
// @NSManaged properties end up being computed; complain if there is
32943294
// an initializer.
3295-
if (var->getParentInitializer()) {
3295+
if (var->getParentExecutableInitializer()) {
32963296
auto &Diags = var->getASTContext().Diags;
32973297
Diags.diagnose(attr->getLocation(), diag::attr_NSManaged_initial_value)
3298-
.highlight(var->getParentInitializer()->getSourceRange());
3298+
.highlight(var->getParentExecutableInitializer()->getSourceRange());
32993299
}
33003300

33013301
// Otherwise, ok.
@@ -3312,13 +3312,22 @@ static void finishNSManagedImplInfo(VarDecl *var,
33123312
}
33133313
}
33143314

3315+
static Expr *getParentExecutableInitializer(VarDecl *var) {
3316+
if (auto *PBD = var->getParentPatternBinding()) {
3317+
const auto i = PBD->getPatternEntryIndexForVarDecl(var);
3318+
return PBD->getExecutableInit(i);
3319+
}
3320+
3321+
return nullptr;
3322+
}
3323+
33153324
static void finishStorageImplInfo(AbstractStorageDecl *storage,
33163325
StorageImplInfo &info) {
33173326
auto dc = storage->getDeclContext();
33183327

33193328
if (auto var = dyn_cast<VarDecl>(storage)) {
33203329
if (!info.hasStorage()) {
3321-
if (auto *init = var->getParentInitializer()) {
3330+
if (auto *init = var->getParentExecutableInitializer()) {
33223331
auto &Diags = var->getASTContext().Diags;
33233332
Diags.diagnose(init->getLoc(), diag::getset_init)
33243333
.highlight(init->getSourceRange());

0 commit comments

Comments
 (0)