Skip to content

Commit 511bd07

Browse files
committed
[SILGen] InitAccessors: Split init accesssor handling into a separate component
The logic is going to be shared when we start supporting init accessor properties without `set`.
1 parent e49e4f9 commit 511bd07

File tree

2 files changed

+119
-40
lines changed

2 files changed

+119
-40
lines changed

lib/SILGen/LValue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class PathComponent {
115115
WritebackPseudoKind, // a fake component to customize writeback
116116
OpenNonOpaqueExistentialKind, // opened class or metatype existential
117117
LogicalKeyPathApplicationKind, // applying a key path
118+
InitAccessorKind, // init accessor
118119

119120
// Translation LValue kinds (a subtype of logical)
120121
OrigToSubstKind, // generic type substitution

lib/SILGen/SILGenLValue.cpp

Lines changed: 118 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,111 @@ namespace {
15471547
}
15481548
};
15491549

1550+
class InitAccessorComponent
1551+
: public AccessorBasedComponent<LogicalPathComponent> {
1552+
public:
1553+
InitAccessorComponent(AbstractStorageDecl *decl,
1554+
SILDeclRef accessor,
1555+
bool isSuper,
1556+
bool isDirectAccessorUse,
1557+
SubstitutionMap substitutions,
1558+
CanType baseFormalType,
1559+
LValueTypeData typeData,
1560+
ArgumentList *subscriptArgList,
1561+
PreparedArguments &&indices,
1562+
bool isOnSelfParameter,
1563+
Optional<ActorIsolation> actorIso)
1564+
: AccessorBasedComponent(
1565+
InitAccessorKind, decl, accessor, isSuper, isDirectAccessorUse,
1566+
substitutions, baseFormalType, typeData, subscriptArgList,
1567+
std::move(indices), isOnSelfParameter, actorIso) {
1568+
assert(getAccessorDecl()->isInitAccessor());
1569+
}
1570+
1571+
InitAccessorComponent(const InitAccessorComponent &copied,
1572+
SILGenFunction &SGF, SILLocation loc)
1573+
: AccessorBasedComponent(copied, SGF, loc) {}
1574+
1575+
void set(SILGenFunction &SGF, SILLocation loc, ArgumentSource &&value,
1576+
ManagedValue base) &&
1577+
override {
1578+
VarDecl *field = cast<VarDecl>(Storage);
1579+
auto fieldType = field->getValueInterfaceType();
1580+
if (!Substitutions.empty()) {
1581+
fieldType = fieldType.subst(Substitutions);
1582+
}
1583+
1584+
// Emit the init accessor function partially applied to the base.
1585+
SILValue initFRef =
1586+
emitPartialInitAccessorReference(SGF, loc, getAccessorDecl());
1587+
1588+
SILValue setterFRef;
1589+
CanSILFunctionType setterTy;
1590+
std::tie(setterFRef, setterTy) = applySetterToBase(
1591+
SGF, loc, SILDeclRef(field->getOpaqueAccessor(AccessorKind::Set)),
1592+
base);
1593+
1594+
auto Mval =
1595+
emitValue(SGF, loc, field, fieldType, std::move(value), setterTy);
1596+
1597+
SGF.B.createAssignOrInit(loc, base.getValue(), Mval.forward(SGF),
1598+
initFRef, setterFRef, AssignOrInitInst::Unknown);
1599+
}
1600+
1601+
RValue get(SILGenFunction &SGF, SILLocation loc, ManagedValue base,
1602+
SGFContext c) &&
1603+
override {
1604+
llvm_unreachable("called get on an init accessor component");
1605+
}
1606+
1607+
std::unique_ptr<LogicalPathComponent>
1608+
clone(SILGenFunction &SGF, SILLocation loc) const override {
1609+
LogicalPathComponent *clone = new InitAccessorComponent(*this, SGF, loc);
1610+
return std::unique_ptr<LogicalPathComponent>(clone);
1611+
}
1612+
1613+
void dump(raw_ostream &OS, unsigned indent) const override {
1614+
printBase(OS, indent, "InitAccessorComponent");
1615+
}
1616+
1617+
/// Compare 'this' lvalue and the 'rhs' lvalue (which is guaranteed to have
1618+
/// the same dynamic PathComponent type as the receiver) to see if they are
1619+
/// identical. If so, there is a conflicting writeback happening, so emit a
1620+
/// diagnostic.
1621+
Optional<AccessStorage> getAccessStorage() const override {
1622+
return AccessStorage{Storage, IsSuper,
1623+
Indices.isNull() ? nullptr : &Indices,
1624+
ArgListForDiagnostics};
1625+
}
1626+
1627+
private:
1628+
SILValue emitPartialInitAccessorReference(SILGenFunction &SGF,
1629+
SILLocation loc,
1630+
AccessorDecl *initAccessor) {
1631+
assert(initAccessor->isInitAccessor());
1632+
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1633+
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1634+
1635+
// If there are no substitutions there is no need to emit partial
1636+
// apply.
1637+
if (Substitutions.empty())
1638+
return initFRef;
1639+
1640+
CanSILFunctionType initTy =
1641+
initFRef->getType().castTo<SILFunctionType>()->substGenericArgs(
1642+
SGF.SGM.M, Substitutions, SGF.getTypeExpansionContext());
1643+
1644+
SILFunctionConventions setterConv(initTy, SGF.SGM.M);
1645+
1646+
// Emit partial apply without argument to produce a substituted
1647+
// init accessor reference.
1648+
PartialApplyInst *initPAI = SGF.B.createPartialApply(
1649+
loc, initFRef, Substitutions, ArrayRef<SILValue>(),
1650+
ParameterConvention::Direct_Guaranteed);
1651+
return SGF.emitManagedRValueWithCleanup(initPAI).getValue();
1652+
}
1653+
};
1654+
15501655
class GetterSetterComponent
15511656
: public AccessorBasedComponent<LogicalPathComponent> {
15521657
public:
@@ -1700,51 +1805,24 @@ namespace {
17001805
assert(!ActorIso && "no support for cross-actor set operations");
17011806
SILDeclRef setter = Accessor;
17021807

1703-
auto emitPartialInitAccessorApply =
1704-
[&](AccessorDecl *initAccessor) -> SILValue {
1705-
assert(initAccessor->isInitAccessor());
1706-
auto initConstant = SGF.getAccessorDeclRef(initAccessor);
1707-
SILValue initFRef = SGF.emitGlobalFunctionRef(loc, initConstant);
1708-
1709-
// If there are no substitutions there is no need to emit partial
1710-
// apply.
1711-
if (Substitutions.empty())
1712-
return initFRef;
1713-
1714-
// Emit partial apply without argument to produce a substituted
1715-
// init accessor reference.
1716-
PartialApplyInst *initPAI = SGF.B.createPartialApply(
1717-
loc, initFRef, Substitutions, ArrayRef<SILValue>(),
1718-
ParameterConvention::Direct_Guaranteed);
1719-
return SGF.emitManagedRValueWithCleanup(initPAI).getValue();
1720-
};
1721-
17221808
if (canRewriteSetAsInitAccessor(SGF)) {
17231809
// Emit an assign_or_init with the allocating initializer function and the
17241810
// setter function as arguments. DefiniteInitialization will then decide
17251811
// between the two functions, depending if it's an init call or a
17261812
// set call.
1727-
VarDecl *field = cast<VarDecl>(Storage);
1728-
auto FieldType = field->getValueInterfaceType();
1729-
if (!Substitutions.empty()) {
1730-
FieldType = FieldType.subst(Substitutions);
1731-
}
1732-
1733-
// Emit the init accessor function partially applied to the base.
1734-
auto initFn = emitPartialInitAccessorApply(
1735-
field->getOpaqueAccessor(AccessorKind::Init));
1736-
1737-
// Emit the set accessor function partially applied to the base.
1738-
SILValue setterFn;
1739-
CanSILFunctionType setterTy;
1740-
std::tie(setterFn, setterTy) =
1741-
applySetterToBase(SGF, loc, Accessor, base);
1742-
1743-
// Create the assign_or_init with the initializer and setter.
1744-
auto Mval =
1745-
emitValue(SGF, loc, field, FieldType, std::move(value), setterTy);
1746-
SGF.B.createAssignOrInit(loc, base.getValue(), Mval.forward(SGF),
1747-
initFn, setterFn, AssignOrInitInst::Unknown);
1813+
SILDeclRef initAccessorRef(Storage->getAccessor(AccessorKind::Init));
1814+
InitAccessorComponent IAC(Storage,
1815+
initAccessorRef,
1816+
IsSuper,
1817+
IsDirectAccessorUse,
1818+
Substitutions,
1819+
BaseFormalType,
1820+
getTypeData(),
1821+
ArgListForDiagnostics,
1822+
std::move(Indices),
1823+
IsOnSelfParameter,
1824+
ActorIso);
1825+
std::move(IAC).set(SGF, loc, std::move(value), base);
17481826
return;
17491827
}
17501828

0 commit comments

Comments
 (0)