Skip to content

Commit b33dbed

Browse files
committed
[SILGen] Teach SIlGen to emit local property wrappers
1 parent 9b2cd5e commit b33dbed

File tree

3 files changed

+78
-21
lines changed

3 files changed

+78
-21
lines changed

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,8 @@ IsSerialized_t SILDeclRef::isSerialized() const {
487487

488488
// Stored property initializers are inlinable if the type is explicitly
489489
// marked as @frozen.
490-
if (isStoredPropertyInitializer() || isPropertyWrapperBackingInitializer()) {
490+
if (isStoredPropertyInitializer() || (isPropertyWrapperBackingInitializer() &&
491+
!d->getDeclContext()->isLocalContext())) {
491492
auto *nominal = cast<NominalTypeDecl>(d->getDeclContext());
492493
auto scope =
493494
nominal->getFormalAccessScope(/*useDC=*/nullptr,

lib/SILGen/SILGenDecl.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Module.h"
2323
#include "swift/AST/NameLookup.h"
2424
#include "swift/AST/ProtocolConformance.h"
25+
#include "swift/AST/PropertyWrappers.h"
2526
#include "swift/Basic/ProfileCounter.h"
2627
#include "swift/SIL/FormalLinkage.h"
2728
#include "swift/SIL/PrettyStackTrace.h"
@@ -1171,13 +1172,36 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD,
11711172
// the initialization. Otherwise, mark it uninitialized for DI to resolve.
11721173
if (auto *Init = PBD->getExecutableInit(idx)) {
11731174
FullExpr Scope(Cleanups, CleanupLocation(Init));
1175+
1176+
auto *var = PBD->getSingleVar();
1177+
if (var && var->getDeclContext()->isLocalContext()) {
1178+
if (auto *orig = var->getOriginalWrappedProperty()) {
1179+
auto wrapperInfo = orig->getPropertyWrapperBackingPropertyInfo();
1180+
Init = wrapperInfo.wrappedValuePlaceholder->getOriginalWrappedValue();
1181+
1182+
auto value = emitRValue(Init);
1183+
emitApplyOfPropertyWrapperBackingInitializer(SILLocation(PBD), orig,
1184+
getForwardingSubstitutionMap(),
1185+
std::move(value))
1186+
.forwardInto(*this, SILLocation(PBD), initialization.get());
1187+
return;
1188+
}
1189+
}
1190+
11741191
emitExprInto(Init, initialization.get(), SILLocation(PBD));
11751192
} else {
11761193
initialization->finishUninitialized(*this);
11771194
}
11781195
}
11791196

11801197
void SILGenFunction::visitPatternBindingDecl(PatternBindingDecl *PBD) {
1198+
// Visit (local) property wrapper backing var first
1199+
auto *singleVar = PBD->getSingleVar();
1200+
if (singleVar && singleVar->hasAttachedPropertyWrapper() &&
1201+
singleVar->getDeclContext()->isLocalContext()) {
1202+
auto *backingVar = singleVar->getPropertyWrapperBackingProperty();
1203+
visitPatternBindingDecl(backingVar->getParentPatternBinding());
1204+
}
11811205

11821206
// Allocate the variables and build up an Initialization over their
11831207
// allocated storage.
@@ -1189,6 +1213,18 @@ void SILGenFunction::visitPatternBindingDecl(PatternBindingDecl *PBD) {
11891213
void SILGenFunction::visitVarDecl(VarDecl *D) {
11901214
// We handle emitting the variable storage when we see the pattern binding.
11911215

1216+
// Visit property wrapper synthesized accessors first.
1217+
if (D->hasAttachedPropertyWrapper() && D->getDeclContext()->isLocalContext()) {
1218+
auto wrapperInfo = D->getPropertyWrapperBackingPropertyInfo();
1219+
if (!wrapperInfo)
1220+
return;
1221+
1222+
SGM.emitPropertyWrapperBackingInitializer(D);
1223+
visit(wrapperInfo.backingVar);
1224+
if (wrapperInfo.projectionVar)
1225+
visit(wrapperInfo.projectionVar);
1226+
}
1227+
11921228
// Emit the variable's accessors.
11931229
D->visitEmittedAccessors([&](AccessorDecl *accessor) {
11941230
SGM.emitFunction(accessor);

lib/SILGen/SILGenLValue.cpp

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,7 +1403,7 @@ namespace {
14031403
assert(getAccessorDecl()->isSetter());
14041404
SILDeclRef setter = Accessor;
14051405

1406-
if (IsOnSelfParameter && canRewriteSetAsPropertyWrapperInit(SGF) &&
1406+
if (canRewriteSetAsPropertyWrapperInit(SGF) &&
14071407
!Storage->isStatic() &&
14081408
isBackingVarVisible(cast<VarDecl>(Storage),
14091409
SGF.FunctionDC)) {
@@ -1434,7 +1434,9 @@ namespace {
14341434

14351435
// Get the address of the storage property.
14361436
ManagedValue proj;
1437-
if (BaseFormalType->mayHaveSuperclass()) {
1437+
if (!BaseFormalType) {
1438+
proj = SGF.maybeEmitValueOfLocalVarDecl(backingVar);
1439+
} else if (BaseFormalType->mayHaveSuperclass()) {
14381440
RefElementComponent REC(backingVar, LValueOptions(), varStorageType,
14391441
typeData);
14401442
proj = std::move(REC).project(SGF, loc, base);
@@ -1471,33 +1473,51 @@ namespace {
14711473
.SILFnType)
14721474
.getValue();
14731475

1474-
} else
1476+
} else {
14751477
setterFRef = SGF.emitGlobalFunctionRef(loc, setter, setterInfo);
1478+
}
1479+
14761480
CanSILFunctionType setterTy = setterFRef->getType().castTo<SILFunctionType>();
14771481
SILFunctionConventions setterConv(setterTy, SGF.SGM.M);
14781482

1479-
SILValue capturedBase;
1480-
unsigned argIdx = setterConv.getNumSILArguments() - 1;
1481-
if (setterConv.getSILArgumentConvention(argIdx).isInoutConvention()) {
1482-
capturedBase = base.getValue();
1483-
} else {
1484-
capturedBase = base.copy(SGF, loc).forward(SGF);
1485-
}
1483+
// Emit captures for the setter
1484+
SmallVector<SILValue, 4> capturedArgs;
1485+
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(setter);
1486+
if (!captureInfo.getCaptures().empty()) {
1487+
SmallVector<ManagedValue, 4> captures;
1488+
SGF.emitCaptures(loc, setter, CaptureEmission::PartialApplication, captures);
14861489

1487-
// If the base is a reference and the setter expects a value, emit a
1488-
// load. This pattern is emitted for property wrappers with a
1489-
// nonmutating setter, for example.
1490-
if (base.getType().isAddress() &&
1491-
base.getType().getObjectType() ==
1492-
setterConv.getSILArgumentType(argIdx,
1493-
SGF.getTypeExpansionContext())) {
1494-
capturedBase = SGF.B.createTrivialLoadOr(
1495-
loc, capturedBase, LoadOwnershipQualifier::Take);
1490+
for (auto capture : captures)
1491+
capturedArgs.push_back(capture.forward(SGF));
1492+
} else {
1493+
assert(base);
1494+
1495+
SILValue capturedBase;
1496+
unsigned argIdx = setterConv.getNumSILArguments() - 1;
1497+
1498+
if (setterConv.getSILArgumentConvention(argIdx).isInoutConvention()) {
1499+
capturedBase = base.getValue();
1500+
} else {
1501+
capturedBase = base.copy(SGF, loc).forward(SGF);
1502+
}
1503+
1504+
// If the base is a reference and the setter expects a value, emit a
1505+
// load. This pattern is emitted for property wrappers with a
1506+
// nonmutating setter, for example.
1507+
if (base.getType().isAddress() &&
1508+
base.getType().getObjectType() ==
1509+
setterConv.getSILArgumentType(argIdx,
1510+
SGF.getTypeExpansionContext())) {
1511+
capturedBase = SGF.B.createTrivialLoadOr(
1512+
loc, capturedBase, LoadOwnershipQualifier::Take);
1513+
}
1514+
1515+
capturedArgs.push_back(capturedBase);
14961516
}
14971517

14981518
PartialApplyInst *setterPAI =
14991519
SGF.B.createPartialApply(loc, setterFRef,
1500-
Substitutions, { capturedBase },
1520+
Substitutions, capturedArgs,
15011521
ParameterConvention::Direct_Guaranteed);
15021522
ManagedValue setterFn = SGF.emitManagedRValueWithCleanup(setterPAI);
15031523

0 commit comments

Comments
 (0)