Skip to content

Commit 75bd889

Browse files
committed
SILGen: Allow extensions to define designated initializers of generic types
Previously, if a generic type had a stored property with a generic type and an initializer expression, we would emit the expression directly in the body of each designated initializer. This is a problem if the designated initializer is defined within an extension (even in the same source file), because extensions have a different set of generic parameters and archetypes. Also, we've had bugs in the past where emitting an expression multiple times didn't work properly. While these might currently all be fixed, this is a tricky case to test and it would be best to avoid it. Fix both problems by emitting the initializer expression inside its own function at the SIL level, and call the initializer function from each designated initializer. I'm using the existing 'variable initializer' mangling for this; it doesn't seem to be used for anything else right now. Currently, the default memberwise initializer does not use this, because the machinery for emitting it is somewhat duplicated and separate from the initializer expressions in user-defined constructors. I'll clean this up in an upcoming patch. Fixes <https://bugs.swift.org/browse/SR-488>.
1 parent f0b2598 commit 75bd889

22 files changed

+284
-59
lines changed

include/swift/AST/Decl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1852,6 +1852,9 @@ class PatternBindingEntry {
18521852
InitCheckedAndRemoved.setInt(
18531853
InitCheckedAndRemoved.getInt() | Flags::Checked);
18541854
}
1855+
1856+
// Return the first variable initialized by this pattern.
1857+
VarDecl *getAnchoringVarDecl() const;
18551858
};
18561859

18571860
/// \brief This decl contains a pattern and optional initializer for a set

include/swift/SIL/SILDeclRef.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,10 @@ struct SILDeclRef {
117117
/// References the generator for a default argument of a function.
118118
DefaultArgGenerator,
119119

120+
/// References the initializer expression for a stored property
121+
/// of a nominal type.
122+
StoredPropertyInitializer,
123+
120124
/// References the ivar initializer for the ClassDecl in loc.
121125
///
122126
/// Only classes that are allocated using Objective-C's allocation
@@ -261,6 +265,11 @@ struct SILDeclRef {
261265
bool isDefaultArgGenerator() const {
262266
return kind == Kind::DefaultArgGenerator;
263267
}
268+
/// True if the SILDeclRef references the initializer for a stored property
269+
/// of a nominal type.
270+
bool isStoredPropertyInitializer() const {
271+
return kind == Kind::StoredPropertyInitializer;
272+
}
264273

265274
/// \brief True if the function should be treated as transparent.
266275
bool isTransparent() const;

lib/AST/Decl.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,13 @@ void PatternBindingEntry::setInit(Expr *E) {
949949
}
950950
}
951951

952+
VarDecl *PatternBindingEntry::getAnchoringVarDecl() const {
953+
SmallVector<VarDecl *, 8> variables;
954+
getPattern()->collectVariables(variables);
955+
assert(variables.size() > 0);
956+
return variables[0];
957+
}
958+
952959
SourceRange PatternBindingDecl::getSourceRange() const {
953960
SourceLoc startLoc = getStartLoc();
954961

lib/IRGen/GenObjC.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,7 @@ namespace {
512512
Selector(SILDeclRef ref) {
513513
switch (ref.kind) {
514514
case SILDeclRef::Kind::DefaultArgGenerator:
515+
case SILDeclRef::Kind::StoredPropertyInitializer:
515516
case SILDeclRef::Kind::EnumElement:
516517
case SILDeclRef::Kind::GlobalAccessor:
517518
case SILDeclRef::Kind::GlobalGetter:

lib/Parse/ParseSIL.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,6 +1053,12 @@ bool SILParser::parseSILDeclRef(SILDeclRef &Result,
10531053
} else if (!ParseState && Id.str() == "ivarinitializer") {
10541054
Kind = SILDeclRef::Kind::IVarInitializer;
10551055
ParseState = 1;
1056+
} else if (!ParseState && Id.str() == "defaultarg") {
1057+
Kind = SILDeclRef::Kind::IVarInitializer;
1058+
ParseState = 1;
1059+
} else if (!ParseState && Id.str() == "propertyinit") {
1060+
Kind = SILDeclRef::Kind::StoredPropertyInitializer;
1061+
ParseState = 1;
10561062
} else if (Id.str() == "foreign") {
10571063
IsObjC = true;
10581064
break;

lib/SIL/SILDeclRef.cpp

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,11 @@ SILDeclRef::SILDeclRef(ValueDecl *vd, SILDeclRef::Kind kind,
152152
"can only create ivar initializer/destroyer SILDeclRef for class");
153153
naturalUncurryLevel = 1;
154154
} else if (auto *var = dyn_cast<VarDecl>(vd)) {
155-
assert((kind == Kind::GlobalAccessor || kind == Kind::GlobalGetter) &&
156-
"can only create GlobalAccessor or GlobalGetter SILDeclRef for var");
155+
assert((kind == Kind::GlobalAccessor ||
156+
kind == Kind::GlobalGetter ||
157+
kind == Kind::StoredPropertyInitializer) &&
158+
"can only create GlobalAccessor, GlobalGetter or "
159+
"StoredPropertyInitializer SILDeclRef for var");
157160

158161
naturalUncurryLevel = 0;
159162
assert(!var->getDeclContext()->isLocalContext() &&
@@ -316,9 +319,14 @@ SILLinkage SILDeclRef::getLinkage(ForDefinition_t forDefinition) const {
316319

317320
// Enum constructors are essentially the same as thunks, they are
318321
// emitted by need and have shared linkage.
319-
if (kind == Kind::EnumElement)
322+
if (isEnumElement())
320323
return SILLinkage::Shared;
321324

325+
// Stored property initializers have hidden linkage, since they are
326+
// not meant to be used from outside of their module.
327+
if (isStoredPropertyInitializer())
328+
return SILLinkage::Hidden;
329+
322330
// Declarations imported from Clang modules have shared linkage.
323331
const SILLinkage ClangLinkage = SILLinkage::Shared;
324332

@@ -353,6 +361,9 @@ bool SILDeclRef::isTransparent() const {
353361
if (isEnumElement())
354362
return true;
355363

364+
if (isStoredPropertyInitializer())
365+
return true;
366+
356367
if (hasAutoClosureExpr())
357368
return true;
358369

@@ -576,12 +587,18 @@ static std::string mangleConstant(SILDeclRef c, StringRef prefix) {
576587
mangler.mangleGlobalGetterEntity(c.getDecl());
577588
return mangler.finalize();
578589

579-
// entity ::= context 'e' index // default arg generator
590+
// entity ::= context 'e' index // default arg generator
580591
case SILDeclRef::Kind::DefaultArgGenerator:
581592
mangler.append(introducer);
582593
mangler.mangleDefaultArgumentEntity(cast<AbstractFunctionDecl>(c.getDecl()),
583594
c.defaultArgIndex);
584595
return mangler.finalize();
596+
597+
// entity ::= 'I' declaration 'i' // stored property initializer
598+
case SILDeclRef::Kind::StoredPropertyInitializer:
599+
mangler.append(introducer);
600+
mangler.mangleInitializerEntity(cast<VarDecl>(c.getDecl()));
601+
return mangler.finalize();
585602
}
586603

587604
llvm_unreachable("bad entity kind!");

lib/SIL/SILFunctionType.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,7 @@ static CanSILFunctionType getNativeSILFunctionType(SILModule &M,
10031003
case SILDeclRef::Kind::GlobalAccessor:
10041004
case SILDeclRef::Kind::GlobalGetter:
10051005
case SILDeclRef::Kind::DefaultArgGenerator:
1006+
case SILDeclRef::Kind::StoredPropertyInitializer:
10061007
case SILDeclRef::Kind::IVarInitializer:
10071008
case SILDeclRef::Kind::IVarDestroyer:
10081009
case SILDeclRef::Kind::EnumElement:
@@ -1472,6 +1473,7 @@ static SelectorFamily getSelectorFamily(SILDeclRef c) {
14721473
case SILDeclRef::Kind::GlobalGetter:
14731474
case SILDeclRef::Kind::IVarDestroyer:
14741475
case SILDeclRef::Kind::DefaultArgGenerator:
1476+
case SILDeclRef::Kind::StoredPropertyInitializer:
14751477
return SelectorFamily::None;
14761478
}
14771479
}
@@ -1653,6 +1655,7 @@ TypeConverter::getDeclRefRepresentation(SILDeclRef c) {
16531655
case SILDeclRef::Kind::GlobalAccessor:
16541656
case SILDeclRef::Kind::GlobalGetter:
16551657
case SILDeclRef::Kind::DefaultArgGenerator:
1658+
case SILDeclRef::Kind::StoredPropertyInitializer:
16561659
return SILFunctionTypeRepresentation::Thin;
16571660

16581661
case SILDeclRef::Kind::Func:
@@ -2319,6 +2322,7 @@ static AbstractFunctionDecl *getBridgedFunction(SILDeclRef declRef) {
23192322
case SILDeclRef::Kind::GlobalAccessor:
23202323
case SILDeclRef::Kind::GlobalGetter:
23212324
case SILDeclRef::Kind::DefaultArgGenerator:
2325+
case SILDeclRef::Kind::StoredPropertyInitializer:
23222326
case SILDeclRef::Kind::IVarInitializer:
23232327
case SILDeclRef::Kind::IVarDestroyer:
23242328
return nullptr;

lib/SIL/SILPrinter.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ void SILDeclRef::print(raw_ostream &OS) const {
322322
case SILDeclRef::Kind::DefaultArgGenerator:
323323
OS << "!defaultarg" << "." << defaultArgIndex;
324324
break;
325+
case SILDeclRef::Kind::StoredPropertyInitializer:
326+
OS << "!propertyinit";
327+
break;
325328
}
326329
if (uncurryLevel != 0)
327330
OS << (isDot ? '.' : '!') << uncurryLevel;

lib/SIL/TypeLowering.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1671,6 +1671,27 @@ static CanAnyFunctionType getDefaultArgGeneratorInterfaceType(
16711671
return CanFunctionType::get(TupleType::getEmpty(context), resultTy);
16721672
}
16731673

1674+
/// Get the type of a stored property initializer, () -> T.
1675+
static CanAnyFunctionType getStoredPropertyInitializerInterfaceType(
1676+
TypeConverter &TC,
1677+
VarDecl *VD,
1678+
ASTContext &context) {
1679+
auto *DC = VD->getDeclContext();
1680+
CanType resultTy =
1681+
ArchetypeBuilder::mapTypeOutOfContext(
1682+
DC, VD->getParentInitializer()->getType())
1683+
->getCanonicalType();
1684+
GenericSignature *sig = DC->getGenericSignatureOfContext();
1685+
1686+
if (sig)
1687+
return CanGenericFunctionType::get(sig->getCanonicalSignature(),
1688+
TupleType::getEmpty(context),
1689+
resultTy,
1690+
GenericFunctionType::ExtInfo());
1691+
1692+
return CanFunctionType::get(TupleType::getEmpty(context), resultTy);
1693+
}
1694+
16741695
/// Get the type of a destructor function.
16751696
static CanAnyFunctionType getDestructorInterfaceType(DestructorDecl *dd,
16761697
bool isDeallocating,
@@ -1868,8 +1889,12 @@ CanAnyFunctionType TypeConverter::makeConstantInterfaceType(SILDeclRef c) {
18681889
}
18691890
case SILDeclRef::Kind::DefaultArgGenerator:
18701891
return getDefaultArgGeneratorInterfaceType(*this,
1871-
cast<AbstractFunctionDecl>(vd),
1872-
c.defaultArgIndex, Context);
1892+
cast<AbstractFunctionDecl>(vd),
1893+
c.defaultArgIndex, Context);
1894+
case SILDeclRef::Kind::StoredPropertyInitializer:
1895+
return getStoredPropertyInitializerInterfaceType(*this,
1896+
cast<VarDecl>(vd),
1897+
Context);
18731898
case SILDeclRef::Kind::IVarInitializer:
18741899
return getIVarInitDestroyerInterfaceType(cast<ClassDecl>(vd),
18751900
c.isForeign, Context, false);
@@ -1926,6 +1951,12 @@ TypeConverter::getConstantContextGenericParams(SILDeclRef c) {
19261951
case SILDeclRef::Kind::DefaultArgGenerator:
19271952
// Use the context generic parameters of the original declaration.
19281953
return getConstantContextGenericParams(SILDeclRef(c.getDecl()));
1954+
case SILDeclRef::Kind::StoredPropertyInitializer:
1955+
// Use the context generic parameters of the containing type.
1956+
return {
1957+
c.getDecl()->getDeclContext()->getGenericParamsOfContext(),
1958+
nullptr,
1959+
};
19291960
}
19301961
}
19311962

lib/SILGen/SILGen.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,21 @@ void SILGenModule::emitDefaultArgGenerator(SILDeclRef constant, Expr *arg) {
877877
});
878878
}
879879

880+
void SILGenModule::
881+
emitStoredPropertyInitialization(PatternBindingDecl *pbd, unsigned i) {
882+
const PatternBindingEntry &pbdEntry = pbd->getPatternList()[i];
883+
auto *var = pbdEntry.getAnchoringVarDecl();
884+
auto *init = pbdEntry.getInit();
885+
886+
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
887+
emitOrDelayFunction(*this, constant, [this,constant,init](SILFunction *f) {
888+
preEmitFunction(constant, init, f, init);
889+
PrettyStackTraceSILFunction X("silgen emitStoredPropertyInitialization", f);
890+
SILGenFunction(*this, *f).emitGeneratorFunction(constant, init);
891+
postEmitFunction(constant, f);
892+
});
893+
}
894+
880895
SILFunction *SILGenModule::emitLazyGlobalInitializer(StringRef funcName,
881896
PatternBindingDecl *binding,
882897
unsigned pbdEntry) {

lib/SILGen/SILGen.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
252252

253253
/// Emits the default argument generator with the given expression.
254254
void emitDefaultArgGenerator(SILDeclRef constant, Expr *arg);
255-
255+
256+
/// Emits the stored property initializer for the given pattern.
257+
void emitStoredPropertyInitialization(PatternBindingDecl *pd, unsigned i);
258+
256259
/// Emits the default argument generator for the given function.
257260
void emitDefaultArgGenerators(SILDeclRef::Loc decl,
258261
ArrayRef<ParameterList*> paramLists);

lib/SILGen/SILGenConstructor.cpp

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,9 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
253253

254254
// If this is not a delegating constructor, emit member initializers.
255255
if (!isDelegating) {
256-
auto nominal = ctor->getDeclContext()
257-
->getAsNominalTypeOrNominalTypeExtensionContext();
258-
emitMemberInitializers(selfDecl, nominal);
256+
auto *dc = ctor->getDeclContext();
257+
auto *nominal = dc->getAsNominalTypeOrNominalTypeExtensionContext();
258+
emitMemberInitializers(dc, selfDecl, nominal);
259259
}
260260

261261
emitProfilerIncrement(ctor->getBody());
@@ -526,7 +526,8 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
526526
// TODO: If we could require Objective-C classes to have an attribute to get
527527
// this behavior, we could avoid runtime overhead here.
528528
VarDecl *selfDecl = ctor->getImplicitSelfDecl();
529-
auto selfClassDecl = ctor->getDeclContext()->getAsClassOrClassExtensionContext();
529+
auto *dc = ctor->getDeclContext();
530+
auto selfClassDecl = dc->getAsClassOrClassExtensionContext();
530531
bool NeedsBoxForSelf = isDelegating ||
531532
(selfClassDecl->hasSuperclass() && !ctor->hasStubImplementation());
532533
bool usesObjCAllocator = Lowering::usesObjCAllocator(selfClassDecl);
@@ -642,7 +643,7 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
642643
// Note that 'self' has been fully initialized at this point.
643644
} else {
644645
// Emit the member initializers.
645-
emitMemberInitializers(selfDecl, selfClassDecl);
646+
emitMemberInitializers(dc, selfDecl, selfClassDecl);
646647
}
647648

648649
emitProfilerIncrement(ctor->getBody());
@@ -841,7 +842,19 @@ static SILValue getBehaviorSetterFn(SILGenFunction &gen, VarDecl *behaviorVar) {
841842
return gen.B.createFunctionRef(behaviorVar, setFn);
842843
}
843844

844-
void SILGenFunction::emitMemberInitializers(VarDecl *selfDecl,
845+
static Type getInitializationTypeInContext(
846+
DeclContext *fromDC, DeclContext *toDC,
847+
Expr *init) {
848+
auto interfaceType =
849+
ArchetypeBuilder::mapTypeOutOfContext(fromDC, init->getType());
850+
auto resultType =
851+
ArchetypeBuilder::mapTypeIntoContext(toDC, interfaceType);
852+
853+
return resultType;
854+
}
855+
856+
void SILGenFunction::emitMemberInitializers(DeclContext *dc,
857+
VarDecl *selfDecl,
845858
NominalTypeDecl *nominal) {
846859
for (auto member : nominal->getMembers()) {
847860
// Find instance pattern binding declarations that have initializers.
@@ -854,7 +867,27 @@ void SILGenFunction::emitMemberInitializers(VarDecl *selfDecl,
854867

855868
// Cleanup after this initialization.
856869
FullExpr scope(Cleanups, entry.getPattern());
857-
emitMemberInit(*this, selfDecl, entry.getPattern(), emitRValue(init));
870+
871+
// Get the substitutions for the constructor context.
872+
ArrayRef<Substitution> subs;
873+
auto *genericParams = dc->getGenericParamsOfContext();
874+
if (genericParams)
875+
subs = genericParams->getForwardingSubstitutions(getASTContext());
876+
877+
// Get the type of the initialization result, in terms
878+
// of the constructor context's archetypes.
879+
CanType resultType = getInitializationTypeInContext(
880+
pbd->getDeclContext(), dc, init)->getCanonicalType();
881+
AbstractionPattern origResultType(resultType);
882+
883+
// FIXME: Can emitMemberInit() share code with
884+
// InitializationForPattern in SILGenDecl.cpp?
885+
RValue result = emitApplyOfStoredPropertyInitializer(
886+
init, entry, subs,
887+
resultType, origResultType,
888+
SGFContext());
889+
890+
emitMemberInit(*this, selfDecl, entry.getPattern(), std::move(result));
858891
}
859892
}
860893

@@ -913,7 +946,7 @@ void SILGenFunction::emitIVarInitializer(SILDeclRef ivarInitializer) {
913946
prepareEpilog(TupleType::getEmpty(getASTContext()), false, cleanupLoc);
914947

915948
// Emit the initializers.
916-
emitMemberInitializers(cd->getDestructor()->getImplicitSelfDecl(), cd);
949+
emitMemberInitializers(cd, selfDecl, cd);
917950

918951
// Return 'self'.
919952
B.createReturn(loc, selfArg);

lib/SILGen/SILGenExpr.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,29 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc,
17241724
ApplyOptions::None, None, None, C);
17251725
}
17261726

1727+
RValue SILGenFunction::emitApplyOfStoredPropertyInitializer(
1728+
SILLocation loc,
1729+
const PatternBindingEntry &entry,
1730+
ArrayRef<Substitution> subs,
1731+
CanType resultType,
1732+
AbstractionPattern origResultType,
1733+
SGFContext C) {
1734+
1735+
VarDecl *var = entry.getAnchoringVarDecl();
1736+
SILDeclRef constant(var, SILDeclRef::Kind::StoredPropertyInitializer);
1737+
auto fnRef = ManagedValue::forUnmanaged(emitGlobalFunctionRef(loc, constant));
1738+
auto fnType = fnRef.getType().castTo<SILFunctionType>();
1739+
1740+
auto substFnType = fnType->substGenericArgs(SGM.M, SGM.M.getSwiftModule(),
1741+
subs);
1742+
1743+
return emitApply(loc, fnRef, subs, {},
1744+
substFnType,
1745+
origResultType,
1746+
resultType,
1747+
ApplyOptions::None, None, None, C);
1748+
}
1749+
17271750
static void emitTupleShuffleExprInto(RValueEmitter &emitter,
17281751
TupleShuffleExpr *E,
17291752
Initialization *outerTupleInit) {

lib/SILGen/SILGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ DeclName SILGenModule::getMagicFunctionName(SILDeclRef ref) {
120120
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
121121
case SILDeclRef::Kind::DefaultArgGenerator:
122122
return getMagicFunctionName(cast<AbstractFunctionDecl>(ref.getDecl()));
123+
case SILDeclRef::Kind::StoredPropertyInitializer:
124+
return getMagicFunctionName(cast<VarDecl>(ref.getDecl())->getDeclContext());
123125
case SILDeclRef::Kind::IVarInitializer:
124126
return getMagicFunctionName(cast<ClassDecl>(ref.getDecl()));
125127
case SILDeclRef::Kind::IVarDestroyer:

0 commit comments

Comments
 (0)