Skip to content

Commit 31cf06b

Browse files
committed
[SILGen] TypeWrappers: Route property wrapper through _storage for managed properties
When property has attached property wrappers and is managed by a type wrapper at the same time it has to be initialized in a special way - instead of using backing property directly (which is not actually a stored property in this scheme) `assign_by_wrapper` instruction has to use a field of a local `_storage` variable which represents underlying storage before `$storage` property could be initialized.
1 parent 862c9d4 commit 31cf06b

File tree

1 file changed

+55
-25
lines changed

1 file changed

+55
-25
lines changed

lib/SILGen/SILGenLValue.cpp

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1588,6 +1588,15 @@ namespace {
15881588
return Mval;
15891589
};
15901590

1591+
auto getTupleFieldIndex =
1592+
[&](VarDecl *var, Identifier fieldName) -> Optional<unsigned> {
1593+
auto *tupleType = var->getInterfaceType()->castTo<TupleType>();
1594+
int fieldIdx = tupleType->getNamedElementId(fieldName);
1595+
if (fieldIdx < 0)
1596+
return None;
1597+
return fieldIdx;
1598+
};
1599+
15911600
if (canRewriteSetAsTypeWrapperInit(SGF)) {
15921601
auto *ctor = cast<ConstructorDecl>(SGF.FunctionDC->getAsDecl());
15931602
auto *field = cast<VarDecl>(Storage);
@@ -1599,20 +1608,19 @@ namespace {
15991608
auto *localVar = ctor->getLocalTypeWrapperStorageVar();
16001609

16011610
// First, we need to find index of the current field in `_storage.
1602-
auto *tempType = localVar->getInterfaceType()->castTo<TupleType>();
1603-
int fieldIdx = tempType->getNamedElementId(field->getName());
1604-
assert(fieldIdx >= 0);
1611+
auto fieldIdx = getTupleFieldIndex(localVar, field->getName());
1612+
assert(fieldIdx.hasValue());
16051613

16061614
// Load `_storage.<name>`
1607-
auto storageBase =
1615+
auto localVarRef =
16081616
SGF.maybeEmitValueOfLocalVarDecl(localVar, AccessKind::Write);
16091617

16101618
auto typeData = getLogicalStorageTypeData(
16111619
SGF.getTypeExpansionContext(), SGF.SGM, getTypeData().AccessKind,
16121620
FieldType->getCanonicalType());
16131621

1614-
TupleElementComponent TEC(fieldIdx, typeData);
1615-
auto storage = std::move(TEC).project(SGF, loc, storageBase);
1622+
TupleElementComponent TEC(*fieldIdx, typeData);
1623+
auto storage = std::move(TEC).project(SGF, loc, localVarRef);
16161624

16171625
// Partially apply the setter so it could be used by assign_by_wrapper
16181626

@@ -1653,29 +1661,51 @@ namespace {
16531661
ValType = ValType.subst(Substitutions);
16541662
}
16551663

1656-
// TODO: revist minimal
1657-
SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType(
1658-
TypeExpansionContext::minimal(), backingVar,
1664+
auto typeData = getLogicalStorageTypeData(
1665+
SGF.getTypeExpansionContext(), SGF.SGM, getTypeData().AccessKind,
16591666
ValType->getCanonicalType());
1660-
auto typeData =
1661-
getLogicalStorageTypeData(SGF.getTypeExpansionContext(), SGF.SGM,
1662-
getTypeData().AccessKind,
1663-
ValType->getCanonicalType());
16641667

1665-
// Get the address of the storage property.
1668+
// Stores the address of the storage property.
16661669
ManagedValue proj;
1667-
if (!BaseFormalType) {
1668-
proj = SGF.maybeEmitValueOfLocalVarDecl(
1669-
backingVar, AccessKind::Write);
1670-
} else if (BaseFormalType->mayHaveSuperclass()) {
1671-
RefElementComponent REC(backingVar, LValueOptions(), varStorageType,
1672-
typeData, /*actorIsolation=*/None);
1673-
proj = std::move(REC).project(SGF, loc, base);
1670+
1671+
// If this is a type wrapper managed property, we emit everything
1672+
// through local `_storage` variable because wrapper property
1673+
// in this case is backed by `$storage` which has to get initialized
1674+
// first.
1675+
if (backingVar->isAccessedViaTypeWrapper()) {
1676+
auto *ctor = cast<ConstructorDecl>(SGF.FunctionDC->getAsDecl());
1677+
auto *localVar = ctor->getLocalTypeWrapperStorageVar();
1678+
1679+
// First, we need to find index of the backing storage field in
1680+
// `_storage`.
1681+
auto fieldIdx = getTupleFieldIndex(localVar, backingVar->getName());
1682+
assert(fieldIdx.hasValue());
1683+
1684+
// Load `_storage.<name>`
1685+
auto localVarRef =
1686+
SGF.maybeEmitValueOfLocalVarDecl(localVar, AccessKind::Write);
1687+
1688+
TupleElementComponent TEC(*fieldIdx, typeData);
1689+
proj = std::move(TEC).project(SGF, loc, localVarRef);
16741690
} else {
1675-
assert(BaseFormalType->getStructOrBoundGenericStruct());
1676-
StructElementComponent SEC(backingVar, varStorageType,
1677-
typeData, /*actorIsolation=*/None);
1678-
proj = std::move(SEC).project(SGF, loc, base);
1691+
// TODO: revist minimal
1692+
SILType varStorageType = SGF.SGM.Types.getSubstitutedStorageType(
1693+
TypeExpansionContext::minimal(), backingVar,
1694+
ValType->getCanonicalType());
1695+
1696+
if (!BaseFormalType) {
1697+
proj =
1698+
SGF.maybeEmitValueOfLocalVarDecl(backingVar, AccessKind::Write);
1699+
} else if (BaseFormalType->mayHaveSuperclass()) {
1700+
RefElementComponent REC(backingVar, LValueOptions(), varStorageType,
1701+
typeData, /*actorIsolation=*/None);
1702+
proj = std::move(REC).project(SGF, loc, base);
1703+
} else {
1704+
assert(BaseFormalType->getStructOrBoundGenericStruct());
1705+
StructElementComponent SEC(backingVar, varStorageType, typeData,
1706+
/*actorIsolation=*/None);
1707+
proj = std::move(SEC).project(SGF, loc, base);
1708+
}
16791709
}
16801710

16811711
// The property wrapper backing initializer forms an instance of

0 commit comments

Comments
 (0)