Skip to content

Commit 1a06313

Browse files
committed
SIL: Fix DynamicSelfType references from inside init accessor
We need the self metatype parameter to correctly lower DynamicSelfType in IRGen, so plumb this through to all calls of init accessors, and inside the prolog of an init accessor definition. This does not break the public ABI, because init accessors are never public. Also for value types, the metatype is thin, so it should not change generated code. For classes we need the metatype in the general case because of `Self`, but hopefully in most cases the init accessor can be inlined away and the value_metatype instruction subject to dead code elimination. Fixes rdar://problem/119822466.
1 parent ab28449 commit 1a06313

File tree

8 files changed

+244
-138
lines changed

8 files changed

+244
-138
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2434,6 +2434,16 @@ static CanSILFunctionType getSILFunctionTypeForInitAccessor(
24342434
ParameterConvention::Indirect_Inout));
24352435
}
24362436

2437+
// Make a new 'self' parameter.
2438+
auto selfInterfaceType = MetatypeType::get(
2439+
accessor->getDeclContext()->getSelfInterfaceType());
2440+
AbstractionPattern origSelfType(genericSig,
2441+
selfInterfaceType->getCanonicalType());
2442+
auto loweredSelfType = TC.getLoweredType(
2443+
origSelfType, selfInterfaceType->getCanonicalType(), context);
2444+
inputs.push_back(SILParameterInfo(loweredSelfType.getASTType(),
2445+
ParameterConvention::Direct_Unowned));
2446+
24372447
SmallVector<SILResultInfo, 8> results;
24382448

24392449
// initialized properties appear as `@out` results because they are

lib/SILGen/SILGenConstructor.cpp

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -91,29 +91,23 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF,
9191
}
9292

9393
static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF,
94-
ValueDecl *ctor) {
94+
ValueDecl *decl) {
9595
// In addition to the declared arguments, the constructor implicitly takes
9696
// the metatype as its first argument, like a static function.
97-
auto ctorFnType = ctor->getInterfaceType()->castTo<AnyFunctionType>();
98-
assert(ctorFnType->getParams().size() == 1 &&
99-
"more than one self parameter?");
100-
auto param = ctorFnType->getParams()[0];
101-
assert(!param.isVariadic() && !param.isInOut());
102-
Type metatype = param.getPlainType();
103-
auto *DC = ctor->getInnermostDeclContext();
104-
auto &AC = SGF.getASTContext();
97+
auto metatypeTy = MetatypeType::get(
98+
decl->getDeclContext()->getSelfInterfaceType());
99+
auto *DC = decl->getInnermostDeclContext();
100+
auto &ctx = SGF.getASTContext();
105101
auto VD =
106-
new (AC) ParamDecl(SourceLoc(), SourceLoc(),
107-
AC.getIdentifier("$metatype"), SourceLoc(),
108-
AC.getIdentifier("$metatype"), DC);
102+
new (ctx) ParamDecl(SourceLoc(), SourceLoc(),
103+
ctx.getIdentifier("$metatype"), SourceLoc(),
104+
ctx.getIdentifier("$metatype"), DC);
109105
VD->setSpecifier(ParamSpecifier::Default);
110-
VD->setInterfaceType(metatype);
106+
VD->setInterfaceType(metatypeTy);
111107

112-
SGF.AllocatorMetatype = SGF.F.begin()->createFunctionArgument(
113-
SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatype)),
108+
return SGF.F.begin()->createFunctionArgument(
109+
SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatypeTy)),
114110
VD);
115-
116-
return SGF.AllocatorMetatype;
117111
}
118112

119113
// FIXME: Consolidate this with SILGenProlog
@@ -273,7 +267,8 @@ static RValue maybeEmitPropertyWrapperInitFromValue(
273267
static void
274268
emitApplyOfInitAccessor(SILGenFunction &SGF, SILLocation loc,
275269
AccessorDecl *accessor, SILValue selfValue,
276-
SILType selfTy, RValue &&initialValue) {
270+
Type selfIfaceTy, SILType selfTy,
271+
RValue &&initialValue) {
277272
SmallVector<SILValue> arguments;
278273

279274
auto emitFieldReference = [&](VarDecl *field, bool forInit = false) {
@@ -297,6 +292,10 @@ emitApplyOfInitAccessor(SILGenFunction &SGF, SILLocation loc,
297292
arguments.push_back(emitFieldReference(property));
298293
}
299294

295+
// The `self` metatype.
296+
auto metatypeTy = MetatypeType::get(accessor->mapTypeIntoContext(selfIfaceTy));
297+
arguments.push_back(SGF.B.createMetatype(loc, SGF.getLoweredType(metatypeTy)));
298+
300299
SubstitutionMap subs;
301300
if (auto *env =
302301
accessor->getDeclContext()->getGenericEnvironmentOfContext()) {
@@ -387,7 +386,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
387386
loweredParams));
388387
}
389388

390-
emitConstructorMetatypeArg(SGF, ctor);
389+
SGF.AllocatorMetatype = emitConstructorMetatypeArg(SGF, ctor);
391390
(void) loweredParams.claimNext();
392391
loweredParams.finish();
393392

@@ -418,8 +417,8 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
418417
assert(elti != eltEnd &&
419418
"number of args does not match number of fields");
420419

421-
emitApplyOfInitAccessor(SGF, Loc, initAccessor, resultSlot, selfTy,
422-
std::move(*elti));
420+
emitApplyOfInitAccessor(SGF, Loc, initAccessor, resultSlot,
421+
selfIfaceTy, selfTy, std::move(*elti));
423422
++elti;
424423
continue;
425424
}
@@ -666,7 +665,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
666665
ctor->getEffectiveThrownErrorType(),
667666
ctor->getThrowsLoc(),
668667
/*ignored parameters*/ 1);
669-
emitConstructorMetatypeArg(*this, ctor);
668+
AllocatorMetatype = emitConstructorMetatypeArg(*this, ctor);
670669

671670
// Make sure we've hopped to the right global actor, if any.
672671
if (ctor->hasAsync()) {
@@ -897,7 +896,7 @@ void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
897896
}
898897

899898
// Emit the metatype argument.
900-
emitConstructorMetatypeArg(*this, element);
899+
AllocatorMetatype = emitConstructorMetatypeArg(*this, element);
901900
(void) loweredParams.claimNext();
902901
loweredParams.finish();
903902

@@ -957,7 +956,8 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
957956
if (ctor->requiresUnavailableDeclABICompatibilityStubs())
958957
emitApplyOfUnavailableCodeReached();
959958

960-
SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor);
959+
AllocatorMetatype = emitConstructorMetatypeArg(*this, ctor);
960+
SILValue selfMetaValue = AllocatorMetatype;
961961

962962
// Allocate the "self" value.
963963
VarDecl *selfDecl = ctor->getImplicitSelfDecl();
@@ -1758,25 +1758,30 @@ void SILGenFunction::emitInitAccessor(AccessorDecl *accessor) {
17581758

17591759
// Emit `newValue` argument.
17601760
emitBasicProlog(accessor,
1761-
accessor->getParameters(), /*selfParam=*/nullptr,
1761+
accessor->getParameters(),
1762+
/*selfParam=*/nullptr,
17621763
TupleType::getEmpty(F.getASTContext()),
17631764
/*errorType=*/llvm::None,
17641765
/*throwsLoc=*/SourceLoc(),
17651766
/*ignored parameters*/
1766-
accessedProperties.size());
1767+
accessedProperties.size() + 1);
17671768

17681769
// Emit arguments for all `accesses` properties.
17691770
if (!accessedProperties.empty()) {
17701771
auto propertyIter = accessedProperties.begin();
17711772
auto propertyArgs = accessorTy->getParameters().slice(
1772-
accessorTy->getNumParameters() - accessedProperties.size());
1773+
accessorTy->getNumParameters() - accessedProperties.size() - 1,
1774+
accessedProperties.size());
17731775

17741776
for (const auto &argument : propertyArgs) {
17751777
createArgument(*propertyIter, getSILTypeInContext(argument, accessorTy));
17761778
++propertyIter;
17771779
}
17781780
}
17791781

1782+
// Emit `self` argument.
1783+
emitConstructorMetatypeArg(*this, accessor);
1784+
17801785
prepareEpilog(accessor,
17811786
accessor->getResultInterfaceType(),
17821787
accessor->getEffectiveThrownErrorType(),

lib/SILGen/SILGenFunction.cpp

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1882,26 +1882,49 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
18821882
if (!substitutions.empty())
18831883
fieldTy = fieldTy.subst(substitutions);
18841884

1885+
auto *initAccessor = field->getOpaqueAccessor(AccessorKind::Init);
1886+
18851887
// Emit the init accessor function partially applied to the base.
18861888
SILValue initFRef = emitGlobalFunctionRef(
1887-
loc, getAccessorDeclRef(field->getOpaqueAccessor(AccessorKind::Init)));
1889+
loc, getAccessorDeclRef(initAccessor));
18881890

18891891
auto initTy = initFRef->getType().castTo<SILFunctionType>();
18901892

1891-
if (!substitutions.empty()) {
1892-
// If there are substitutions we need to emit partial apply to
1893-
// apply substitutions to the init accessor reference type.
1894-
initTy = initTy->substGenericArgs(SGM.M, substitutions,
1895-
getTypeExpansionContext());
1893+
// If there are substitutions we need to emit partial apply to
1894+
// apply substitutions to the init accessor reference type.
1895+
initTy = initTy->substGenericArgs(SGM.M, substitutions,
1896+
getTypeExpansionContext());
1897+
1898+
// Emit partial apply with self metatype argument to produce a substituted
1899+
// init accessor reference.
1900+
auto selfTy = selfValue.getType().getASTType();
1901+
auto metatypeTy = MetatypeType::get(selfTy);
18961902

1897-
// Emit partial apply without argument to produce a substituted
1898-
// init accessor reference.
1899-
PartialApplyInst *initPAI =
1900-
B.createPartialApply(loc, initFRef, substitutions, ArrayRef<SILValue>(),
1901-
ParameterConvention::Direct_Guaranteed);
1902-
initFRef = emitManagedRValueWithCleanup(initPAI).getValue();
1903+
SILValue selfMetatype;
1904+
if (selfTy->getClassOrBoundGenericClass()) {
1905+
selfMetatype = B.createValueMetatype(loc, getLoweredType(metatypeTy),
1906+
selfValue).getValue();
1907+
} else {
1908+
selfMetatype = B.createMetatype(loc, getLoweredType(metatypeTy));
19031909
}
19041910

1911+
auto expectedSelfTy = initAccessor->getDeclContext()->getSelfInterfaceType()
1912+
.subst(substitutions);
1913+
1914+
// This should only happen in the invalid case where we attempt to initialize
1915+
// superclass storage from a subclass initializer. However, we shouldn't
1916+
// crash, so emit the appropriate cast so that we can recover and diagnose
1917+
// later.
1918+
if (!expectedSelfTy->isEqual(selfTy)) {
1919+
selfMetatype = B.createUpcast(loc, selfMetatype,
1920+
getLoweredType(MetatypeType::get(expectedSelfTy)));
1921+
}
1922+
PartialApplyInst *initPAI =
1923+
B.createPartialApply(loc, initFRef, substitutions, selfMetatype,
1924+
ParameterConvention::Direct_Guaranteed,
1925+
PartialApplyInst::OnStackKind::OnStack);
1926+
initFRef = emitManagedRValueWithCleanup(initPAI).getValue();
1927+
19051928
// Check whether value is supposed to be passed indirectly and
19061929
// materialize if required.
19071930
{
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend -emit-ir %s
2+
3+
public class C {
4+
private var _count: Int
5+
6+
var count: Int {
7+
@storageRestrictions(initializes: _count)
8+
init {
9+
print(Self.self) // crash here
10+
_count = newValue
11+
}
12+
get { _count }
13+
set { }
14+
}
15+
16+
init() {
17+
count = 0
18+
}
19+
}
20+
21+
let c = C()

test/Interpreter/init_accessors.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,3 +922,35 @@ do {
922922
// CHECK-NEXT: init accessor is called: 42
923923
// CHECK-NEXT: nonmutating set called: 0
924924
// CHECK-NEXT: test-nonmutating-set-4: TestNonMutatingSetCustom(_count: 42)
925+
926+
do {
927+
class Base {
928+
var _count: Int
929+
930+
var count: Int {
931+
@storageRestrictions(initializes: _count)
932+
init {
933+
print("init accessor with Self = \(Self.self)")
934+
_count = newValue
935+
}
936+
937+
get { _count }
938+
939+
set {}
940+
}
941+
942+
init() {
943+
count = 42
944+
}
945+
}
946+
947+
class Sub: Base {}
948+
949+
print("- init accessor vs dynamic Self")
950+
_ = Base()
951+
_ = Sub()
952+
}
953+
954+
// CHECK-NEXT: - init accessor vs dynamic Self
955+
// CHECK-NEXT: init accessor with Self = Base
956+
// CHECK-NEXT: init accessor with Self = Sub

0 commit comments

Comments
 (0)