Skip to content

Commit b6edb09

Browse files
authored
Merge pull request #67294 from xedin/default-init-via-accessor-in-custom-initializers
[Sema/SIL] InitAccessors: Support default initialization of init accessor properties
2 parents 7db5fe1 + ff19286 commit b6edb09

12 files changed

+674
-142
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1459,6 +1459,49 @@ emitAndStoreInitialValueInto(SILGenFunction &SGF,
14591459
std::move(result).forwardInto(SGF, loc, init);
14601460
}
14611461

1462+
void SILGenFunction::emitMemberInitializationViaInitAccessor(
1463+
DeclContext *dc, VarDecl *selfDecl, PatternBindingDecl *member,
1464+
SubstitutionMap subs) {
1465+
auto *var = member->getSingleVar();
1466+
assert(var->hasInitAccessor());
1467+
1468+
auto init = member->getExecutableInit(0);
1469+
if (!init)
1470+
return;
1471+
1472+
auto *varPattern = member->getPattern(0);
1473+
1474+
// Cleanup after this initialization.
1475+
FullExpr scope(Cleanups, varPattern);
1476+
1477+
auto resultType =
1478+
getInitializationTypeInContext(member->getDeclContext(), dc, varPattern);
1479+
1480+
RValue initResult = emitApplyOfStoredPropertyInitializer(
1481+
init, var, subs, resultType.second, resultType.first, SGFContext());
1482+
1483+
SILLocation loc(init);
1484+
loc.markAutoGenerated();
1485+
1486+
auto selfValue = emitSelfForMemberInit(*this, varPattern, selfDecl);
1487+
1488+
ManagedValue selfRef = selfValue;
1489+
if (selfValue.isLValue()) {
1490+
auto accessToSelf =
1491+
B.createBeginAccess(loc, selfValue.getValue(), SILAccessKind::Modify,
1492+
SILAccessEnforcement::Unknown,
1493+
/*noNestedConflict=*/false,
1494+
/*fromBuiltin=*/false);
1495+
selfRef = ManagedValue::forUnmanaged(accessToSelf);
1496+
}
1497+
1498+
emitAssignOrInit(loc, selfRef, var,
1499+
std::move(initResult).getAsSingleValue(*this, loc), subs);
1500+
1501+
if (selfValue.isLValue())
1502+
B.createEndAccess(loc, selfRef.getValue(), /*aborted=*/false);
1503+
}
1504+
14621505
void SILGenFunction::emitMemberInitializers(DeclContext *dc,
14631506
VarDecl *selfDecl,
14641507
NominalTypeDecl *nominal) {
@@ -1469,11 +1512,12 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
14691512
if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
14701513
if (pbd->isStatic()) continue;
14711514

1472-
// Skip properties with init accessors, they could only be used
1473-
// explicitly and in memberwise initializers.
1515+
// Emit default initialization for an init accessor property.
14741516
if (auto *var = pbd->getSingleVar()) {
1475-
if (var->hasInitAccessor())
1517+
if (var->hasInitAccessor()) {
1518+
emitMemberInitializationViaInitAccessor(dc, selfDecl, pbd, subs);
14761519
continue;
1520+
}
14771521
}
14781522

14791523
for (auto i : range(pbd->getNumPatternEntries())) {

lib/SILGen/SILGenFunction.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,3 +1754,111 @@ ParamDecl *SILGenFunction::isMappedToInitAccessorArgument(VarDecl *property) {
17541754

17551755
return arg->second;
17561756
}
1757+
1758+
SILValue
1759+
SILGenFunction::emitApplyOfSetterToBase(SILLocation loc, SILDeclRef setter,
1760+
ManagedValue base,
1761+
SubstitutionMap substitutions) {
1762+
auto setterFRef = [&]() -> SILValue {
1763+
auto setterInfo = getConstantInfo(getTypeExpansionContext(), setter);
1764+
if (setter.hasDecl() && setter.getDecl()->shouldUseObjCDispatch()) {
1765+
// Emit a thunk we might have to bridge arguments.
1766+
auto foreignSetterThunk = setter.asForeign(false);
1767+
return emitDynamicMethodRef(
1768+
loc, foreignSetterThunk,
1769+
SGM.Types
1770+
.getConstantInfo(getTypeExpansionContext(),
1771+
foreignSetterThunk)
1772+
.SILFnType)
1773+
.getValue();
1774+
}
1775+
1776+
return emitGlobalFunctionRef(loc, setter, setterInfo);
1777+
}();
1778+
1779+
auto getSetterType = [&](SILValue setterFRef) {
1780+
CanSILFunctionType setterTy =
1781+
setterFRef->getType().castTo<SILFunctionType>();
1782+
return setterTy->substGenericArgs(SGM.M, substitutions,
1783+
getTypeExpansionContext());
1784+
};
1785+
1786+
SILFunctionConventions setterConv(getSetterType(setterFRef), SGM.M);
1787+
1788+
// Emit captures for the setter
1789+
SmallVector<SILValue, 4> capturedArgs;
1790+
auto captureInfo = SGM.Types.getLoweredLocalCaptures(setter);
1791+
if (!captureInfo.getCaptures().empty()) {
1792+
SmallVector<ManagedValue, 4> captures;
1793+
emitCaptures(loc, setter, CaptureEmission::AssignByWrapper, captures);
1794+
1795+
for (auto capture : captures)
1796+
capturedArgs.push_back(capture.forward(*this));
1797+
} else {
1798+
assert(base);
1799+
1800+
SILValue capturedBase;
1801+
unsigned argIdx = setterConv.getNumSILArguments() - 1;
1802+
1803+
if (setterConv.getSILArgumentConvention(argIdx).isInoutConvention()) {
1804+
capturedBase = base.getValue();
1805+
} else if (base.getType().isAddress() &&
1806+
base.getType().getObjectType() ==
1807+
setterConv.getSILArgumentType(argIdx,
1808+
getTypeExpansionContext())) {
1809+
// If the base is a reference and the setter expects a value, emit a
1810+
// load. This pattern is emitted for property wrappers with a
1811+
// nonmutating setter, for example.
1812+
capturedBase = B.createTrivialLoadOr(loc, base.getValue(),
1813+
LoadOwnershipQualifier::Copy);
1814+
} else {
1815+
capturedBase = base.copy(*this, loc).forward(*this);
1816+
}
1817+
1818+
capturedArgs.push_back(capturedBase);
1819+
}
1820+
1821+
PartialApplyInst *setterPAI =
1822+
B.createPartialApply(loc, setterFRef, substitutions, capturedArgs,
1823+
ParameterConvention::Direct_Guaranteed);
1824+
return emitManagedRValueWithCleanup(setterPAI).getValue();
1825+
}
1826+
1827+
void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
1828+
VarDecl *field, ManagedValue newValue,
1829+
SubstitutionMap substitutions) {
1830+
auto fieldTy = field->getValueInterfaceType();
1831+
if (!substitutions.empty())
1832+
fieldTy = fieldTy.subst(substitutions);
1833+
1834+
// Emit the init accessor function partially applied to the base.
1835+
SILValue initFRef = emitGlobalFunctionRef(
1836+
loc, getAccessorDeclRef(field->getOpaqueAccessor(AccessorKind::Init)));
1837+
if (!substitutions.empty()) {
1838+
// If there are substitutions we need to emit partial apply to
1839+
// apply substitutions to the init accessor reference type.
1840+
auto initTy =
1841+
initFRef->getType().castTo<SILFunctionType>()->substGenericArgs(
1842+
SGM.M, substitutions, getTypeExpansionContext());
1843+
1844+
SILFunctionConventions setterConv(initTy, SGM.M);
1845+
1846+
// Emit partial apply without argument to produce a substituted
1847+
// init accessor reference.
1848+
PartialApplyInst *initPAI =
1849+
B.createPartialApply(loc, initFRef, substitutions, ArrayRef<SILValue>(),
1850+
ParameterConvention::Direct_Guaranteed);
1851+
initFRef = emitManagedRValueWithCleanup(initPAI).getValue();
1852+
}
1853+
1854+
SILValue setterFRef;
1855+
if (auto *setter = field->getOpaqueAccessor(AccessorKind::Set)) {
1856+
setterFRef = emitApplyOfSetterToBase(loc, SILDeclRef(setter), selfValue,
1857+
substitutions);
1858+
} else {
1859+
setterFRef = SILUndef::get(initFRef->getType(), F);
1860+
}
1861+
1862+
B.createAssignOrInit(loc, selfValue.getValue(), newValue.forward(*this),
1863+
initFRef, setterFRef, AssignOrInitInst::Unknown);
1864+
}

lib/SILGen/SILGenFunction.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
802802
void emitMemberInitializers(DeclContext *dc, VarDecl *selfDecl,
803803
NominalTypeDecl *nominal);
804804

805+
void emitMemberInitializationViaInitAccessor(DeclContext *dc,
806+
VarDecl *selfDecl,
807+
PatternBindingDecl *member,
808+
SubstitutionMap subs);
809+
805810
/// Emit a method that initializes the ivars of a class.
806811
void emitIVarInitializer(SILDeclRef ivarInitializer);
807812

@@ -814,6 +819,22 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
814819
/// value assignment.
815820
void emitInitAccessor(AccessorDecl *accessor);
816821

822+
/// Generates code to emit the given setter reference to the given base value.
823+
SILValue emitApplyOfSetterToBase(SILLocation loc, SILDeclRef setter,
824+
ManagedValue base,
825+
SubstitutionMap substitutions);
826+
827+
/// Emit `assign_or_init` instruction that is going to either initialize
828+
/// or assign the given value to the given field.
829+
///
830+
/// \param loc The location to use for the instruction.
831+
/// \param selfValue The 'self' value.
832+
/// \param field The field to assign or initialize.
833+
/// \param newValue the value to assign/initialize the field with.
834+
/// \param substitutions The substitutions to apply to initializer and setter.
835+
void emitAssignOrInit(SILLocation loc, ManagedValue selfValue, VarDecl *field,
836+
ManagedValue newValue, SubstitutionMap substitutions);
837+
817838
/// Generates code to destroy the instance variables of a class.
818839
///
819840
/// \param selfValue The 'self' value.

0 commit comments

Comments
 (0)