Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions lib/SIL/IR/SILFunctionType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2434,6 +2434,16 @@ static CanSILFunctionType getSILFunctionTypeForInitAccessor(
ParameterConvention::Indirect_Inout));
}

// Make a new 'self' parameter.
auto selfInterfaceType = MetatypeType::get(
accessor->getDeclContext()->getSelfInterfaceType());
AbstractionPattern origSelfType(genericSig,
selfInterfaceType->getCanonicalType());
auto loweredSelfType = TC.getLoweredType(
origSelfType, selfInterfaceType->getCanonicalType(), context);
inputs.push_back(SILParameterInfo(loweredSelfType.getASTType(),
ParameterConvention::Direct_Unowned));

SmallVector<SILResultInfo, 8> results;

// initialized properties appear as `@out` results because they are
Expand Down
59 changes: 32 additions & 27 deletions lib/SILGen/SILGenConstructor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,29 +91,23 @@ static ManagedValue emitManagedParameter(SILGenFunction &SGF,
}

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

SGF.AllocatorMetatype = SGF.F.begin()->createFunctionArgument(
SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatype)),
return SGF.F.begin()->createFunctionArgument(
SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatypeTy)),
VD);

return SGF.AllocatorMetatype;
}

// FIXME: Consolidate this with SILGenProlog
Expand Down Expand Up @@ -273,7 +267,8 @@ static RValue maybeEmitPropertyWrapperInitFromValue(
static void
emitApplyOfInitAccessor(SILGenFunction &SGF, SILLocation loc,
AccessorDecl *accessor, SILValue selfValue,
SILType selfTy, RValue &&initialValue) {
Type selfIfaceTy, SILType selfTy,
RValue &&initialValue) {
SmallVector<SILValue> arguments;

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

// The `self` metatype.
auto metatypeTy = MetatypeType::get(accessor->mapTypeIntoContext(selfIfaceTy));
arguments.push_back(SGF.B.createMetatype(loc, SGF.getLoweredType(metatypeTy)));

SubstitutionMap subs;
if (auto *env =
accessor->getDeclContext()->getGenericEnvironmentOfContext()) {
Expand Down Expand Up @@ -387,7 +386,7 @@ static void emitImplicitValueConstructor(SILGenFunction &SGF,
loweredParams));
}

emitConstructorMetatypeArg(SGF, ctor);
SGF.AllocatorMetatype = emitConstructorMetatypeArg(SGF, ctor);
(void) loweredParams.claimNext();
loweredParams.finish();

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

emitApplyOfInitAccessor(SGF, Loc, initAccessor, resultSlot, selfTy,
std::move(*elti));
emitApplyOfInitAccessor(SGF, Loc, initAccessor, resultSlot,
selfIfaceTy, selfTy, std::move(*elti));
++elti;
continue;
}
Expand Down Expand Up @@ -666,7 +665,7 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
ctor->getEffectiveThrownErrorType(),
ctor->getThrowsLoc(),
/*ignored parameters*/ 1);
emitConstructorMetatypeArg(*this, ctor);
AllocatorMetatype = emitConstructorMetatypeArg(*this, ctor);

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

// Emit the metatype argument.
emitConstructorMetatypeArg(*this, element);
AllocatorMetatype = emitConstructorMetatypeArg(*this, element);
(void) loweredParams.claimNext();
loweredParams.finish();

Expand Down Expand Up @@ -957,7 +956,8 @@ void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
if (ctor->requiresUnavailableDeclABICompatibilityStubs())
emitApplyOfUnavailableCodeReached();

SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor);
AllocatorMetatype = emitConstructorMetatypeArg(*this, ctor);
SILValue selfMetaValue = AllocatorMetatype;

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

// Emit `newValue` argument.
emitBasicProlog(accessor,
accessor->getParameters(), /*selfParam=*/nullptr,
accessor->getParameters(),
/*selfParam=*/nullptr,
TupleType::getEmpty(F.getASTContext()),
/*errorType=*/llvm::None,
/*throwsLoc=*/SourceLoc(),
/*ignored parameters*/
accessedProperties.size());
accessedProperties.size() + 1);

// Emit arguments for all `accesses` properties.
if (!accessedProperties.empty()) {
auto propertyIter = accessedProperties.begin();
auto propertyArgs = accessorTy->getParameters().slice(
accessorTy->getNumParameters() - accessedProperties.size());
accessorTy->getNumParameters() - accessedProperties.size() - 1,
accessedProperties.size());

for (const auto &argument : propertyArgs) {
createArgument(*propertyIter, getSILTypeInContext(argument, accessorTy));
++propertyIter;
}
}

// Emit `self` argument.
emitConstructorMetatypeArg(*this, accessor);

prepareEpilog(accessor,
accessor->getResultInterfaceType(),
accessor->getEffectiveThrownErrorType(),
Expand Down
47 changes: 35 additions & 12 deletions lib/SILGen/SILGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1882,26 +1882,49 @@ void SILGenFunction::emitAssignOrInit(SILLocation loc, ManagedValue selfValue,
if (!substitutions.empty())
fieldTy = fieldTy.subst(substitutions);

auto *initAccessor = field->getOpaqueAccessor(AccessorKind::Init);

// Emit the init accessor function partially applied to the base.
SILValue initFRef = emitGlobalFunctionRef(
loc, getAccessorDeclRef(field->getOpaqueAccessor(AccessorKind::Init)));
loc, getAccessorDeclRef(initAccessor));

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

if (!substitutions.empty()) {
// If there are substitutions we need to emit partial apply to
// apply substitutions to the init accessor reference type.
initTy = initTy->substGenericArgs(SGM.M, substitutions,
getTypeExpansionContext());
// If there are substitutions we need to emit partial apply to
// apply substitutions to the init accessor reference type.
initTy = initTy->substGenericArgs(SGM.M, substitutions,
getTypeExpansionContext());

// Emit partial apply with self metatype argument to produce a substituted
// init accessor reference.
auto selfTy = selfValue.getType().getASTType();
auto metatypeTy = MetatypeType::get(selfTy);

// Emit partial apply without argument to produce a substituted
// init accessor reference.
PartialApplyInst *initPAI =
B.createPartialApply(loc, initFRef, substitutions, ArrayRef<SILValue>(),
ParameterConvention::Direct_Guaranteed);
initFRef = emitManagedRValueWithCleanup(initPAI).getValue();
SILValue selfMetatype;
if (selfTy->getClassOrBoundGenericClass()) {
selfMetatype = B.createValueMetatype(loc, getLoweredType(metatypeTy),
selfValue).getValue();
} else {
selfMetatype = B.createMetatype(loc, getLoweredType(metatypeTy));
}

auto expectedSelfTy = initAccessor->getDeclContext()->getSelfInterfaceType()
.subst(substitutions);

// This should only happen in the invalid case where we attempt to initialize
// superclass storage from a subclass initializer. However, we shouldn't
// crash, so emit the appropriate cast so that we can recover and diagnose
// later.
if (!expectedSelfTy->isEqual(selfTy)) {
selfMetatype = B.createUpcast(loc, selfMetatype,
getLoweredType(MetatypeType::get(expectedSelfTy)));
}
PartialApplyInst *initPAI =
B.createPartialApply(loc, initFRef, substitutions, selfMetatype,
ParameterConvention::Direct_Guaranteed,
PartialApplyInst::OnStackKind::OnStack);
initFRef = emitManagedRValueWithCleanup(initPAI).getValue();

// Check whether value is supposed to be passed indirectly and
// materialize if required.
{
Expand Down
21 changes: 21 additions & 0 deletions test/IRGen/init_accessor_dynamic_self.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %target-swift-frontend -emit-ir %s

public class C {
private var _count: Int

var count: Int {
@storageRestrictions(initializes: _count)
init {
print(Self.self) // crash here
_count = newValue
}
get { _count }
set { }
}

init() {
count = 0
}
}

let c = C()
32 changes: 32 additions & 0 deletions test/Interpreter/init_accessors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -922,3 +922,35 @@ do {
// CHECK-NEXT: init accessor is called: 42
// CHECK-NEXT: nonmutating set called: 0
// CHECK-NEXT: test-nonmutating-set-4: TestNonMutatingSetCustom(_count: 42)

do {
class Base {
var _count: Int

var count: Int {
@storageRestrictions(initializes: _count)
init {
print("init accessor with Self = \(Self.self)")
_count = newValue
}

get { _count }

set {}
}

init() {
count = 42
}
}

class Sub: Base {}

print("- init accessor vs dynamic Self")
_ = Base()
_ = Sub()
}

// CHECK-NEXT: - init accessor vs dynamic Self
// CHECK-NEXT: init accessor with Self = Base
// CHECK-NEXT: init accessor with Self = Sub
Loading