Skip to content

Commit 593c236

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 10027fb commit 593c236

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
@@ -6656,6 +6656,15 @@ bool VarDecl::isLazilyInitializedGlobal() const {
66566656
return !isTopLevelGlobal();
66576657
}
66586658

6659+
Expr *VarDecl::getParentExecutableInitializer() const {
6660+
if (auto *PBD = getParentPatternBinding()) {
6661+
const auto i = PBD->getPatternEntryIndexForVarDecl(this);
6662+
return PBD->getExecutableInit(i);
6663+
}
6664+
6665+
return nullptr;
6666+
}
6667+
66596668
SourceRange VarDecl::getSourceRange() const {
66606669
if (auto Param = dyn_cast<ParamDecl>(this))
66616670
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
@@ -646,7 +646,8 @@ class LetValueInitialization : public Initialization {
646646

647647
assert(!isa<ParamDecl>(vd)
648648
&& "should not bind function params on this path");
649-
if (vd->getParentPatternBinding() && !vd->getParentInitializer()) {
649+
if (vd->getParentPatternBinding() &&
650+
!vd->getParentExecutableInitializer()) {
650651
// If this is a let-value without an initializer, then we need a temporary
651652
// buffer. DI will make sure it is only assigned to once.
652653
needsTemporaryBuffer = true;
@@ -1433,8 +1434,8 @@ SILGenFunction::emitInitializationForVarDecl(VarDecl *vd, bool forceImmutable,
14331434
// If the variable has no initial value, emit a mark_uninitialized instruction
14341435
// so that DI tracks and enforces validity of it.
14351436
bool isUninitialized =
1436-
vd->getParentPatternBinding() && !vd->getParentInitializer();
1437-
1437+
vd->getParentPatternBinding() && !vd->getParentExecutableInitializer();
1438+
14381439
// If this is a global variable, initialize it without allocations or
14391440
// cleanups.
14401441
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
@@ -1324,12 +1324,12 @@ Optional<unsigned> swift::expandAccessors(
13241324
if (accessor->isObservingAccessor())
13251325
continue;
13261326

1327-
// If any non-observing accessor was added, remove the initializer if
1328-
// there is one.
1327+
// If any non-observing accessor was added, mark the initializer as
1328+
// subsumed.
13291329
if (auto var = dyn_cast<VarDecl>(storage)) {
13301330
if (auto binding = var->getParentPatternBinding()) {
13311331
unsigned index = binding->getPatternEntryIndexForVarDecl(var);
1332-
binding->setInit(index, nullptr);
1332+
binding->setInitializerSubsumed(index);
13331333
break;
13341334
}
13351335
}

lib/Sema/TypeCheckStorage.cpp

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

33023302
// Otherwise, ok.
@@ -3313,13 +3313,22 @@ static void finishNSManagedImplInfo(VarDecl *var,
33133313
}
33143314
}
33153315

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

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

0 commit comments

Comments
 (0)