blob: 0598e6de0e509a13af6dac4c39ee4d265b06cfec [file] [log] [blame]
//===--- SILGenConstructor.cpp - SILGen for constructors ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "ArgumentSource.h"
#include "Conversion.h"
#include "Initialization.h"
#include "LValue.h"
#include "RValue.h"
#include "SILGenFunction.h"
#include "SILGenFunctionBuilder.h"
#include "Scope.h"
#include "swift/AST/ASTMangler.h"
#include "swift/AST/ForeignErrorConvention.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/Basic/Defer.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SIL/TypeLowering.h"
using namespace swift;
using namespace Lowering;
static SILValue emitConstructorMetatypeArg(SILGenFunction &SGF,
ValueDecl *ctor) {
// 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 VD =
new (AC) ParamDecl(SourceLoc(), SourceLoc(),
AC.getIdentifier("$metatype"), SourceLoc(),
AC.getIdentifier("$metatype"), DC);
VD->setSpecifier(ParamSpecifier::Default);
VD->setInterfaceType(metatype);
SGF.AllocatorMetatype = SGF.F.begin()->createFunctionArgument(
SGF.getLoweredTypeForFunctionArgument(DC->mapTypeIntoContext(metatype)),
VD);
return SGF.AllocatorMetatype;
}
// FIXME: Consolidate this with SILGenProlog
static RValue emitImplicitValueConstructorArg(SILGenFunction &SGF,
SILLocation loc,
CanType interfaceType,
DeclContext *DC) {
auto type = DC->mapTypeIntoContext(interfaceType)->getCanonicalType();
// Restructure tuple arguments.
if (auto tupleTy = dyn_cast<TupleType>(interfaceType)) {
RValue tuple(type);
for (auto fieldType : tupleTy.getElementTypes())
tuple.addElement(emitImplicitValueConstructorArg(SGF, loc, fieldType, DC));
return tuple;
}
auto &AC = SGF.getASTContext();
auto VD = new (AC) ParamDecl(SourceLoc(), SourceLoc(),
AC.getIdentifier("$implicit_value"),
SourceLoc(),
AC.getIdentifier("$implicit_value"),
DC);
VD->setSpecifier(ParamSpecifier::Default);
VD->setInterfaceType(interfaceType);
auto argType = SGF.getLoweredTypeForFunctionArgument(type);
auto *arg = SGF.F.begin()->createFunctionArgument(argType, VD);
ManagedValue mvArg;
if (arg->getArgumentConvention().isOwnedConvention()) {
mvArg = SGF.emitManagedRValueWithCleanup(arg);
} else {
mvArg = ManagedValue::forUnmanaged(arg);
}
// This can happen if the value is resilient in the calling convention
// but not resilient locally.
if (argType.isLoadable(SGF.F) && argType.isAddress()) {
if (mvArg.isPlusOne(SGF))
mvArg = SGF.B.createLoadTake(loc, mvArg);
else
mvArg = SGF.B.createLoadBorrow(loc, mvArg);
}
return RValue(SGF, loc, type, mvArg);
}
/// If the field has a property wrapper for which we will need to call the
/// wrapper type's init(wrappedValue:, ...), call the function that performs
/// that initialization and return the result. Otherwise, return \c arg.
static RValue maybeEmitPropertyWrapperInitFromValue(
SILGenFunction &SGF,
SILLocation loc,
VarDecl *field,
SubstitutionMap subs,
RValue &&arg) {
auto originalProperty = field->getOriginalWrappedProperty();
if (!originalProperty ||
!originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
return std::move(arg);
auto wrapperInfo = originalProperty->getPropertyWrapperBackingPropertyInfo();
if (!wrapperInfo || !wrapperInfo.initializeFromOriginal)
return std::move(arg);
return SGF.emitApplyOfPropertyWrapperBackingInitializer(loc, originalProperty,
subs, std::move(arg));
}
static SubstitutionMap getSubstitutionsForPropertyInitializer(
DeclContext *dc,
NominalTypeDecl *nominal) {
// We want a substitution list written in terms of the generic
// signature of the type, with replacement archetypes from the
// constructor's context (which might be in an extension of
// the type, which adds additional generic requirements).
if (auto *genericEnv = dc->getGenericEnvironmentOfContext()) {
// Generate a set of substitutions for the initialization function,
// whose generic signature is that of the type context, and whose
// replacement types are the archetypes of the initializer itself.
return SubstitutionMap::get(
nominal->getGenericSignatureOfContext(),
[&](SubstitutableType *type) {
if (auto gp = type->getAs<GenericTypeParamType>()) {
return genericEnv->mapTypeIntoContext(gp);
}
return Type(type);
},
LookUpConformanceInModule(dc->getParentModule()));
}
return SubstitutionMap();
}
static void emitImplicitValueConstructor(SILGenFunction &SGF,
ConstructorDecl *ctor) {
RegularLocation Loc(ctor);
Loc.markAutoGenerated();
AssertingManualScope functionLevelScope(SGF.Cleanups,
CleanupLocation::get(Loc));
// FIXME: Handle 'self' along with the other arguments.
auto *paramList = ctor->getParameters();
auto *selfDecl = ctor->getImplicitSelfDecl();
auto selfIfaceTy = selfDecl->getInterfaceType();
SILType selfTy = SGF.getLoweredTypeForFunctionArgument(selfDecl->getType());
// Emit the indirect return argument, if any.
SILValue resultSlot;
if (SILModuleConventions::isReturnedIndirectlyInSIL(selfTy, SGF.SGM.M)) {
auto &AC = SGF.getASTContext();
auto VD = new (AC) ParamDecl(SourceLoc(), SourceLoc(),
AC.getIdentifier("$return_value"),
SourceLoc(),
AC.getIdentifier("$return_value"),
ctor);
VD->setSpecifier(ParamSpecifier::InOut);
VD->setInterfaceType(selfIfaceTy);
resultSlot =
SGF.F.begin()->createFunctionArgument(selfTy.getAddressType(), VD);
}
// Emit the elementwise arguments.
SmallVector<RValue, 4> elements;
for (size_t i = 0, size = paramList->size(); i < size; ++i) {
auto &param = paramList->get(i);
elements.push_back(
emitImplicitValueConstructorArg(
SGF, Loc, param->getInterfaceType()->getCanonicalType(), ctor));
}
emitConstructorMetatypeArg(SGF, ctor);
auto *decl = selfTy.getStructOrBoundGenericStruct();
assert(decl && "not a struct?!");
auto subs = getSubstitutionsForPropertyInitializer(decl, decl);
// If we have an indirect return slot, initialize it in-place.
if (resultSlot) {
auto elti = elements.begin(), eltEnd = elements.end();
for (VarDecl *field : decl->getStoredProperties()) {
auto fieldTy =
selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext());
SILValue slot =
SGF.B.createStructElementAddr(Loc, resultSlot, field,
fieldTy.getAddressType());
InitializationPtr init(new KnownAddressInitialization(slot));
// If it's memberwise initialized, do so now.
if (field->isMemberwiseInitialized(/*preferDeclaredProperties=*/false)) {
assert(elti != eltEnd &&
"number of args does not match number of fields");
(void)eltEnd;
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
RValue arg = std::move(*elti);
// If the stored property has an attached result builder and its
// type is not a function type, the argument is a noescape closure
// that needs to be called.
if (field->getResultBuilderType()) {
if (!field->getValueInterfaceType()
->lookThroughAllOptionalTypes()->is<AnyFunctionType>()) {
auto resultTy = cast<FunctionType>(arg.getType()).getResult();
arg = SGF.emitMonomorphicApply(
Loc, std::move(arg).getAsSingleValue(SGF, Loc), { }, resultTy,
resultTy, ApplyOptions::None, None, None);
}
}
maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs,
std::move(arg))
.forwardInto(SGF, Loc, init.get());
++elti;
} else {
assert(field->getType()->getReferenceStorageReferent()->isEqual(
field->getParentInitializer()->getType()) &&
"Initialization of field with mismatched type!");
// Cleanup after this initialization.
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
// If this is a property wrapper backing storage var that isn't
// memberwise initialized and has an original wrapped value, apply
// the property wrapper backing initializer.
if (auto *wrappedVar = field->getOriginalWrappedProperty()) {
auto wrappedInfo = wrappedVar->getPropertyWrapperBackingPropertyInfo();
auto *placeholder = wrappedInfo.wrappedValuePlaceholder;
if (placeholder && placeholder->getOriginalWrappedValue()) {
auto arg = SGF.emitRValue(placeholder->getOriginalWrappedValue());
maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs,
std::move(arg))
.forwardInto(SGF, Loc, init.get());
continue;
}
}
SGF.emitExprInto(field->getParentInitializer(), init.get());
}
}
SGF.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
SGF.emitEmptyTuple(Loc), std::move(functionLevelScope));
return;
}
// Otherwise, build a struct value directly from the elements.
SmallVector<SILValue, 4> eltValues;
auto elti = elements.begin(), eltEnd = elements.end();
for (VarDecl *field : decl->getStoredProperties()) {
auto fieldTy =
selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext());
RValue value;
FullExpr scope(SGF.Cleanups, field->getParentPatternBinding());
// If it's memberwise initialized, do so now.
if (field->isMemberwiseInitialized(/*preferDeclaredProperties=*/false)) {
assert(elti != eltEnd && "number of args does not match number of fields");
(void)eltEnd;
value = std::move(*elti);
++elti;
} else {
// Otherwise, use its initializer.
assert(field->isParentInitialized());
Expr *init = field->getParentInitializer();
// If this is a property wrapper backing storage var that isn't
// memberwise initialized, use the original wrapped value if it exists.
if (auto *wrappedVar = field->getOriginalWrappedProperty()) {
auto wrappedInfo = wrappedVar->getPropertyWrapperBackingPropertyInfo();
auto *placeholder = wrappedInfo.wrappedValuePlaceholder;
if (placeholder && placeholder->getOriginalWrappedValue()) {
init = placeholder->getOriginalWrappedValue();
}
}
value = SGF.emitRValue(init);
}
// Cleanup after this initialization.
SILValue v = maybeEmitPropertyWrapperInitFromValue(SGF, Loc, field, subs,
std::move(value))
.forwardAsSingleStorageValue(SGF, fieldTy, Loc);
eltValues.push_back(v);
}
SILValue selfValue = SGF.B.createStruct(Loc, selfTy, eltValues);
SGF.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
selfValue, std::move(functionLevelScope));
return;
}
void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);
if (ctor->isMemberwiseInitializer())
return emitImplicitValueConstructor(*this, ctor);
// True if this constructor delegates to a peer constructor with self.init().
bool isDelegating = ctor->getDelegatingOrChainedInitKind().initKind ==
BodyInitKind::Delegating;
// Get the 'self' decl and type.
VarDecl *selfDecl = ctor->getImplicitSelfDecl();
auto &lowering = getTypeLowering(selfDecl->getType());
// Decide if we need to do extra work to warn on unsafe behavior in pre-Swift-5
// modes.
MarkUninitializedInst::Kind MUIKind;
if (isDelegating) {
MUIKind = MarkUninitializedInst::DelegatingSelf;
} else if (getASTContext().isSwiftVersionAtLeast(5)) {
MUIKind = MarkUninitializedInst::RootSelf;
} else {
auto *dc = ctor->getParent();
if (isa<ExtensionDecl>(dc) &&
dc->getSelfStructDecl()->getParentModule() != dc->getParentModule()) {
MUIKind = MarkUninitializedInst::CrossModuleRootSelf;
} else {
MUIKind = MarkUninitializedInst::RootSelf;
}
}
// Allocate the local variable for 'self'.
emitLocalVariableWithCleanup(selfDecl, MUIKind)->finishInitialization(*this);
SILValue selfLV = VarLocs[selfDecl].value;
// Emit the prolog.
emitProlog(ctor->getParameters(),
/*selfParam=*/nullptr,
ctor->getResultInterfaceType(), ctor,
ctor->hasThrows(),
ctor->getThrowsLoc());
emitConstructorMetatypeArg(*this, ctor);
// Create a basic block to jump to for the implicit 'self' return.
// We won't emit this until after we've emitted the body.
// The epilog takes a void return because the return of 'self' is implicit.
prepareEpilog(false, ctor->hasThrows(), CleanupLocation(ctor));
// If the constructor can fail, set up an alternative epilog for constructor
// failure.
SILBasicBlock *failureExitBB = nullptr;
SILArgument *failureExitArg = nullptr;
auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType());
auto &resultLowering = getTypeLowering(resultType);
if (ctor->isFailable()) {
SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter);
// On failure, we'll clean up everything (except self, which should have
// been cleaned up before jumping here) and return nil instead.
SILGenSavedInsertionPoint savedIP(*this, failureBB,
FunctionSection::Postmatter);
failureExitBB = createBasicBlock();
Cleanups.emitCleanupsForReturn(ctor, IsForUnwind);
// Return nil.
if (F.getConventions().hasIndirectSILResults()) {
// Inject 'nil' into the indirect return.
assert(F.getIndirectResults().size() == 1);
B.createInjectEnumAddr(ctor, F.getIndirectResults()[0],
getASTContext().getOptionalNoneDecl());
B.createBranch(ctor, failureExitBB);
B.setInsertionPoint(failureExitBB);
B.createReturn(ctor, emitEmptyTuple(ctor));
} else {
// Pass 'nil' as the return value to the exit BB.
failureExitArg = failureExitBB->createPhiArgument(
resultLowering.getLoweredType(), OwnershipKind::Owned);
SILValue nilResult =
B.createEnum(ctor, SILValue(), getASTContext().getOptionalNoneDecl(),
resultLowering.getLoweredType());
B.createBranch(ctor, failureExitBB, nilResult);
B.setInsertionPoint(failureExitBB);
B.createReturn(ctor, failureExitArg);
}
FailDest = JumpDest(failureBB, Cleanups.getCleanupsDepth(), ctor);
}
// If this is not a delegating constructor, emit member initializers.
if (!isDelegating) {
auto *typeDC = ctor->getDeclContext();
auto *nominal = typeDC->getSelfNominalTypeDecl();
emitMemberInitializers(ctor, selfDecl, nominal);
}
emitProfilerIncrement(ctor->getTypecheckedBody());
// Emit the constructor body.
emitStmt(ctor->getTypecheckedBody());
// Build a custom epilog block, since the AST representation of the
// constructor decl (which has no self in the return type) doesn't match the
// SIL representation.
SILValue selfValue;
{
SILGenSavedInsertionPoint savedIP(*this, ReturnDest.getBlock());
assert(B.getInsertionBB()->empty() && "Epilog already set up?");
auto cleanupLoc = CleanupLocation::get(ctor);
if (!F.getConventions().hasIndirectSILResults()) {
// Otherwise, load and return the final 'self' value.
selfValue = lowering.emitLoad(B, cleanupLoc, selfLV,
LoadOwnershipQualifier::Copy);
// Inject the self value into an optional if the constructor is failable.
if (ctor->isFailable()) {
selfValue = B.createEnum(cleanupLoc, selfValue,
getASTContext().getOptionalSomeDecl(),
getLoweredLoadableType(resultType));
}
} else {
// If 'self' is address-only, copy 'self' into the indirect return slot.
assert(F.getConventions().getNumIndirectSILResults() == 1
&& "no indirect return for address-only ctor?!");
// Get the address to which to store the result.
SILValue completeReturnAddress = F.getIndirectResults()[0];
SILValue returnAddress;
if (!ctor->isFailable()) {
// For non-failable initializers, store to the return address directly.
returnAddress = completeReturnAddress;
} else {
// If this is a failable initializer, project out the payload.
returnAddress = B.createInitEnumDataAddr(cleanupLoc,
completeReturnAddress,
getASTContext().getOptionalSomeDecl(),
selfLV->getType());
}
// We have to do a non-take copy because someone else may be using the
// box (e.g. someone could have closed over it).
B.createCopyAddr(cleanupLoc, selfLV, returnAddress,
IsNotTake, IsInitialization);
// Inject the enum tag if the result is optional because of failability.
if (ctor->isFailable()) {
// Inject the 'Some' tag.
B.createInjectEnumAddr(cleanupLoc, completeReturnAddress,
getASTContext().getOptionalSomeDecl());
}
}
}
// Finally, emit the epilog and post-matter.
auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true);
// Finish off the epilog by returning. If this is a failable ctor, then we
// actually jump to the failure epilog to keep the invariant that there is
// only one SIL return instruction per SIL function.
if (B.hasValidInsertionPoint()) {
if (!failureExitBB) {
// If we're not returning self, then return () since we're returning Void.
if (!selfValue) {
SILLocation loc(ctor);
loc.markAutoGenerated();
selfValue = emitEmptyTuple(loc);
}
B.createReturn(returnLoc, selfValue);
} else {
if (selfValue)
B.createBranch(returnLoc, failureExitBB, selfValue);
else
B.createBranch(returnLoc, failureExitBB);
}
}
}
void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
Type enumIfaceTy = element->getParentEnum()->getDeclaredInterfaceType();
Type enumTy = F.mapTypeIntoContext(enumIfaceTy);
auto &enumTI =
SGM.Types.getTypeLowering(enumTy, TypeExpansionContext::minimal());
RegularLocation Loc(element);
CleanupLocation CleanupLoc(element);
Loc.markAutoGenerated();
// Emit the indirect return slot.
std::unique_ptr<Initialization> dest;
if (enumTI.isAddressOnly() && silConv.useLoweredAddresses()) {
auto &AC = getASTContext();
auto VD = new (AC) ParamDecl(SourceLoc(), SourceLoc(),
AC.getIdentifier("$return_value"),
SourceLoc(),
AC.getIdentifier("$return_value"),
element->getDeclContext());
VD->setSpecifier(ParamSpecifier::InOut);
VD->setInterfaceType(enumIfaceTy);
auto resultSlot =
F.begin()->createFunctionArgument(enumTI.getLoweredType(), VD);
dest = std::unique_ptr<Initialization>(
new KnownAddressInitialization(resultSlot));
}
Scope scope(Cleanups, CleanupLoc);
// Emit the exploded constructor argument.
ArgumentSource payload;
if (element->hasAssociatedValues()) {
auto eltArgTy = element->getArgumentInterfaceType()->getCanonicalType();
RValue arg = emitImplicitValueConstructorArg(*this, Loc, eltArgTy, element);
payload = ArgumentSource(Loc, std::move(arg));
}
// Emit the metatype argument.
emitConstructorMetatypeArg(*this, element);
// If possible, emit the enum directly into the indirect return.
SGFContext C = (dest ? SGFContext(dest.get()) : SGFContext());
ManagedValue mv = emitInjectEnum(Loc, std::move(payload),
enumTI.getLoweredType(),
element, C);
// Return the enum.
auto ReturnLoc = ImplicitReturnLocation::getImplicitReturnLoc(Loc);
if (dest) {
if (!mv.isInContext()) {
dest->copyOrInitValueInto(*this, Loc, mv, /*isInit*/ true);
dest->finishInitialization(*this);
}
scope.pop();
B.createReturn(ReturnLoc, emitEmptyTuple(Loc));
} else {
assert(enumTI.isLoadable() || !silConv.useLoweredAddresses());
SILValue result = mv.ensurePlusOne(*this, ReturnLoc).forward(*this);
scope.pop();
B.createReturn(ReturnLoc, result);
}
}
bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
// If the root class was implemented in Objective-C, use Objective-C's
// allocation methods because they may have been overridden.
return theClass->usesObjCObjectModel();
}
void SILGenFunction::emitClassConstructorAllocator(ConstructorDecl *ctor) {
assert(!ctor->isFactoryInit() && "factories should not be emitted here");
// Emit the prolog. Since we're just going to forward our args directly
// to the initializer, don't allocate local variables for them.
RegularLocation Loc(ctor);
Loc.markAutoGenerated();
// Forward the constructor arguments.
// FIXME: Handle 'self' along with the other body patterns.
SmallVector<SILValue, 8> args;
bindParametersForForwarding(ctor->getParameters(), args);
SILValue selfMetaValue = emitConstructorMetatypeArg(*this, ctor);
// Allocate the "self" value.
VarDecl *selfDecl = ctor->getImplicitSelfDecl();
SILType selfTy = getLoweredType(selfDecl->getType());
assert(selfTy.hasReferenceSemantics() &&
"can't emit a value type ctor here");
// Use alloc_ref to allocate the object.
// TODO: allow custom allocation?
// FIXME: should have a cleanup in case of exception
auto selfClassDecl = ctor->getDeclContext()->getSelfClassDecl();
SILValue selfValue;
// Allocate the 'self' value.
bool useObjCAllocation = usesObjCAllocator(selfClassDecl);
if (ctor->hasClangNode() ||
ctor->shouldUseObjCDispatch() ||
ctor->isConvenienceInit()) {
assert(ctor->hasClangNode() || ctor->isObjC());
// For an allocator thunk synthesized for an @objc convenience initializer
// or imported Objective-C init method, allocate using the metatype.
SILValue allocArg = selfMetaValue;
// When using Objective-C allocation, convert the metatype
// argument to an Objective-C metatype.
if (useObjCAllocation) {
auto metaTy = allocArg->getType().castTo<MetatypeType>();
metaTy = CanMetatypeType::get(metaTy.getInstanceType(),
MetatypeRepresentation::ObjC);
allocArg = B.createThickToObjCMetatype(Loc, allocArg,
getLoweredType(metaTy));
}
selfValue = B.createAllocRefDynamic(Loc, allocArg, selfTy,
useObjCAllocation, {}, {});
} else {
assert(ctor->isDesignatedInit());
// For a designated initializer, we know that the static type being
// allocated is the type of the class that defines the designated
// initializer.
F.setIsExactSelfClass(IsExactSelfClass);
selfValue = B.createAllocRef(Loc, selfTy, useObjCAllocation, false,
ArrayRef<SILType>(), ArrayRef<SILValue>());
}
args.push_back(selfValue);
// Call the initializer. Always use the Swift entry point, which will be a
// bridging thunk if we're calling ObjC.
auto initConstant = SILDeclRef(ctor, SILDeclRef::Kind::Initializer);
ManagedValue initVal;
SILType initTy;
// Call the initializer.
auto subMap = F.getForwardingSubstitutionMap();
std::tie(initVal, initTy)
= emitSiblingMethodRef(Loc, selfValue, initConstant, subMap);
SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this),
initTy, subMap, args);
emitProfilerIncrement(ctor->getTypecheckedBody());
// Return the initialized 'self'.
B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
initedSelfValue);
}
static void emitDefaultActorInitialization(SILGenFunction &SGF,
SILLocation loc,
ManagedValue self) {
auto &ctx = SGF.getASTContext();
auto builtinName = ctx.getIdentifier(
getBuiltinName(BuiltinValueKind::InitializeDefaultActor));
auto resultTy = SGF.SGM.Types.getEmptyTupleType();
FullExpr scope(SGF.Cleanups, CleanupLocation::get(loc));
SGF.B.createBuiltin(loc, builtinName, resultTy, /*subs*/{},
{ self.borrow(SGF, loc).getValue() });
}
void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);
assert(ctor->getTypecheckedBody() && "Class constructor without a body?");
// True if this constructor delegates to a peer constructor with self.init().
bool isDelegating = false;
if (!ctor->hasStubImplementation()) {
isDelegating = ctor->getDelegatingOrChainedInitKind().initKind ==
BodyInitKind::Delegating;
}
// Set up the 'self' argument. If this class has a superclass, we set up
// self as a box. This allows "self reassignment" to happen in super init
// method chains, which is important for interoperating with Objective-C
// classes. We also use a box for delegating constructors, since the
// delegated-to initializer may also replace self.
//
// TODO: If we could require Objective-C classes to have an attribute to get
// this behavior, we could avoid runtime overhead here.
VarDecl *selfDecl = ctor->getImplicitSelfDecl();
auto *dc = ctor->getDeclContext();
auto selfClassDecl = dc->getSelfClassDecl();
bool NeedsBoxForSelf = isDelegating ||
(selfClassDecl->hasSuperclass() && !ctor->hasStubImplementation());
bool usesObjCAllocator = Lowering::usesObjCAllocator(selfClassDecl);
// If needed, mark 'self' as uninitialized so that DI knows to
// enforce its DI properties on stored properties.
MarkUninitializedInst::Kind MUKind;
if (isDelegating) {
if (ctor->isObjC())
MUKind = MarkUninitializedInst::DelegatingSelfAllocated;
else
MUKind = MarkUninitializedInst::DelegatingSelf;
} else if (selfClassDecl->requiresStoredPropertyInits() &&
usesObjCAllocator) {
// Stored properties will be initialized in a separate
// .cxx_construct method called by the Objective-C runtime.
assert(selfClassDecl->hasSuperclass() &&
"Cannot use ObjC allocation without a superclass");
MUKind = MarkUninitializedInst::DerivedSelfOnly;
} else if (selfClassDecl->hasSuperclass())
MUKind = MarkUninitializedInst::DerivedSelf;
else
MUKind = MarkUninitializedInst::RootSelf;
if (NeedsBoxForSelf) {
// Allocate the local variable for 'self'.
emitLocalVariableWithCleanup(selfDecl, MUKind)->finishInitialization(*this);
}
// Emit the prolog for the non-self arguments.
// FIXME: Handle self along with the other body patterns.
uint16_t ArgNo = emitProlog(ctor->getParameters(), /*selfParam=*/nullptr,
TupleType::getEmpty(F.getASTContext()), ctor,
ctor->hasThrows(), ctor->getThrowsLoc());
SILType selfTy = getLoweredLoadableType(selfDecl->getType());
ManagedValue selfArg = B.createInputFunctionArgument(selfTy, selfDecl);
if (!NeedsBoxForSelf) {
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
SILDebugVariable DbgVar(selfDecl->isLet(), ++ArgNo);
B.createDebugValue(PrologueLoc, selfArg.getValue(), DbgVar);
}
// Initialize the default-actor instance.
if (selfClassDecl->isRootDefaultActor() && !isDelegating) {
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
emitDefaultActorInitialization(*this, PrologueLoc, selfArg);
}
if (!ctor->hasStubImplementation()) {
assert(selfTy.hasReferenceSemantics() &&
"can't emit a value type ctor here");
if (NeedsBoxForSelf) {
SILLocation prologueLoc = RegularLocation(ctor);
prologueLoc.markAsPrologue();
B.emitStoreValueOperation(prologueLoc, selfArg.forward(*this),
VarLocs[selfDecl].value,
StoreOwnershipQualifier::Init);
} else {
selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind);
VarLocs[selfDecl] = VarLoc::get(selfArg.getValue());
}
}
// Prepare the end of initializer location.
SILLocation endOfInitLoc = RegularLocation(ctor);
endOfInitLoc.pointToEnd();
// Create a basic block to jump to for the implicit 'self' return.
// We won't emit the block until after we've emitted the body.
prepareEpilog(false, ctor->hasThrows(),
CleanupLocation::get(endOfInitLoc));
auto resultType = ctor->mapTypeIntoContext(ctor->getResultInterfaceType());
// If the constructor can fail, set up an alternative epilog for constructor
// failure.
SILBasicBlock *failureExitBB = nullptr;
SILArgument *failureExitArg = nullptr;
auto &resultLowering = getTypeLowering(resultType);
if (ctor->isFailable()) {
SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter);
RegularLocation loc(ctor);
loc.markAutoGenerated();
// On failure, we'll clean up everything and return nil instead.
SILGenSavedInsertionPoint savedIP(*this, failureBB,
FunctionSection::Postmatter);
failureExitBB = createBasicBlock();
failureExitArg = failureExitBB->createPhiArgument(
resultLowering.getLoweredType(), OwnershipKind::Owned);
Cleanups.emitCleanupsForReturn(ctor, IsForUnwind);
SILValue nilResult =
B.createEnum(loc, SILValue(), getASTContext().getOptionalNoneDecl(),
resultLowering.getLoweredType());
B.createBranch(loc, failureExitBB, nilResult);
B.setInsertionPoint(failureExitBB);
B.createReturn(loc, failureExitArg);
FailDest = JumpDest(failureBB, Cleanups.getCleanupsDepth(), ctor);
}
// Handle member initializers.
if (isDelegating) {
// A delegating initializer does not initialize instance
// variables.
} else if (ctor->hasStubImplementation()) {
// Nor does a stub implementation.
} else if (selfClassDecl->requiresStoredPropertyInits() &&
usesObjCAllocator) {
// When the class requires all stored properties to have initial
// values and we're using Objective-C's allocation, stored
// properties are initialized via the .cxx_construct method, which
// will be called by the runtime.
// Note that 'self' has been fully initialized at this point.
} else {
// Emit the member initializers.
emitMemberInitializers(ctor, selfDecl, selfClassDecl);
}
emitProfilerIncrement(ctor->getTypecheckedBody());
// Emit the constructor body.
emitStmt(ctor->getTypecheckedBody());
// Emit the call to super.init() right before exiting from the initializer.
if (NeedsBoxForSelf) {
if (auto *SI = ctor->getSuperInitCall()) {
B.setInsertionPoint(ReturnDest.getBlock());
emitRValue(SI);
B.emitBlock(B.splitBlockForFallthrough(), ctor);
ReturnDest = JumpDest(B.getInsertionBB(),
ReturnDest.getDepth(),
ReturnDest.getCleanupLocation());
B.clearInsertionPoint();
}
}
CleanupStateRestorationScope SelfCleanupSave(Cleanups);
// Build a custom epilog block, since the AST representation of the
// constructor decl (which has no self in the return type) doesn't match the
// SIL representation.
{
// Ensure that before we add additional cleanups, that we have emitted all
// cleanups at this point.
assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(),
ReturnDest.getDepth()) &&
"emitting epilog in wrong scope");
SILGenSavedInsertionPoint savedIP(*this, ReturnDest.getBlock());
auto cleanupLoc = CleanupLocation(ctor);
// If we're using a box for self, reload the value at the end of the init
// method.
if (NeedsBoxForSelf) {
ManagedValue storedSelf =
ManagedValue::forUnmanaged(VarLocs[selfDecl].value);
selfArg = B.createLoadCopy(cleanupLoc, storedSelf);
} else {
// We have to do a retain because we are returning the pointer +1.
//
// SEMANTIC ARC TODO: When the verifier is complete, we will need to
// change this to selfArg = B.emitCopyValueOperation(...). Currently due
// to the way that SILGen performs folding of copy_value, destroy_value,
// the returned selfArg may be deleted causing us to have a
// dead-pointer. Instead just use the old self value since we have a
// class.
selfArg = B.createCopyValue(cleanupLoc, selfArg);
}
// Inject the self value into an optional if the constructor is failable.
if (ctor->isFailable()) {
RegularLocation loc(ctor);
loc.markAutoGenerated();
selfArg = B.createEnum(loc, selfArg,
getASTContext().getOptionalSomeDecl(),
getLoweredLoadableType(resultType));
}
// Save our cleanup state. We want all other potential cleanups to fire, but
// not this one.
if (selfArg.hasCleanup())
SelfCleanupSave.pushCleanupState(selfArg.getCleanup(),
CleanupState::Dormant);
// Translate our cleanup to the new top cleanup.
//
// This is needed to preserve the invariant in getEpilogBB that when
// cleanups are emitted, everything above ReturnDest.getDepth() has been
// emitted. This is not true if we use ManagedValue and friends in the
// epilogBB, thus the translation. We perform the same check above that
// getEpilogBB performs to ensure that we still do not have the same
// problem.
ReturnDest = std::move(ReturnDest).translate(getTopCleanup());
}
// Emit the epilog and post-matter.
auto returnLoc = emitEpilog(ctor, /*UsesCustomEpilog*/true);
// Unpop our selfArg cleanup, so we can forward.
std::move(SelfCleanupSave).pop();
// Finish off the epilog by returning. If this is a failable ctor, then we
// actually jump to the failure epilog to keep the invariant that there is
// only one SIL return instruction per SIL function.
if (B.hasValidInsertionPoint()) {
if (failureExitBB)
B.createBranch(returnLoc, failureExitBB, selfArg.forward(*this));
else
B.createReturn(returnLoc, selfArg.forward(*this));
}
}
static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc,
VarDecl *selfDecl) {
CanType selfFormalType = selfDecl->getType()->getCanonicalType();
if (selfFormalType->hasReferenceSemantics())
return SGF.emitRValueForDecl(loc, selfDecl, selfFormalType,
AccessSemantics::DirectToStorage,
SGFContext::AllowImmediatePlusZero)
.getAsSingleValue(SGF, loc);
else
return SGF.emitAddressOfLocalVarDecl(loc, selfDecl, selfFormalType,
SGFAccessKind::Write);
}
// FIXME: Can emitMemberInit() share code with InitializationForPattern in
// SILGenDecl.cpp? Note that this version operates on stored properties of
// types, whereas the former only knows how to handle local bindings, but
// we could generalize it.
static InitializationPtr
emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl, Pattern *pattern) {
switch (pattern->getKind()) {
case PatternKind::Paren:
return emitMemberInit(SGF, selfDecl,
cast<ParenPattern>(pattern)->getSubPattern());
case PatternKind::Tuple: {
TupleInitialization *init = new TupleInitialization();
auto tuple = cast<TuplePattern>(pattern);
for (auto &elt : tuple->getElements()) {
init->SubInitializations.push_back(
emitMemberInit(SGF, selfDecl, elt.getPattern()));
}
return InitializationPtr(init);
}
case PatternKind::Named: {
auto named = cast<NamedPattern>(pattern);
auto self = emitSelfForMemberInit(SGF, pattern, selfDecl);
auto *field = named->getDecl();
auto selfTy = self.getType();
auto fieldTy =
selfTy.getFieldType(field, SGF.SGM.M, SGF.getTypeExpansionContext());
SILValue slot;
if (auto *structDecl = dyn_cast<StructDecl>(field->getDeclContext())) {
slot = SGF.B.createStructElementAddr(pattern, self.forward(SGF), field,
fieldTy.getAddressType());
} else {
assert(isa<ClassDecl>(field->getDeclContext()));
slot = SGF.B.createRefElementAddr(pattern, self.forward(SGF), field,
fieldTy.getAddressType());
}
return InitializationPtr(new KnownAddressInitialization(slot));
}
case PatternKind::Any:
return InitializationPtr(new BlackHoleInitialization());;
case PatternKind::Typed:
return emitMemberInit(SGF, selfDecl,
cast<TypedPattern>(pattern)->getSubPattern());
case PatternKind::Binding:
return emitMemberInit(SGF, selfDecl,
cast<BindingPattern>(pattern)->getSubPattern());
#define PATTERN(Name, Parent)
#define REFUTABLE_PATTERN(Name, Parent) case PatternKind::Name:
#include "swift/AST/PatternNodes.def"
llvm_unreachable("Refutable pattern in stored property pattern binding");
}
}
static std::pair<AbstractionPattern, CanType>
getInitializationTypeInContext(
DeclContext *fromDC, DeclContext *toDC,
Pattern *pattern) {
auto interfaceType = pattern->getType()->mapTypeOutOfContext();
// If this pattern is initializing the backing storage for a property
// with an attached wrapper that is initialized with `=`, the
// initialization type is the original property type.
if (auto singleVar = pattern->getSingleVar()) {
if (auto originalProperty = singleVar->getOriginalWrappedProperty()) {
if (originalProperty->isPropertyMemberwiseInitializedWithWrappedType())
interfaceType = originalProperty->getPropertyWrapperInitValueInterfaceType();
}
}
AbstractionPattern origType(
fromDC->getGenericSignatureOfContext().getCanonicalSignature(),
interfaceType->getCanonicalType());
auto substType = toDC->mapTypeIntoContext(interfaceType)->getCanonicalType();
return std::make_pair(origType, substType);
}
static void
emitAndStoreInitialValueInto(SILGenFunction &SGF,
SILLocation loc,
PatternBindingDecl *pbd, unsigned i,
SubstitutionMap subs,
AbstractionPattern origType,
CanType substType,
Initialization *init) {
bool injectIntoWrapper = false;
if (auto singleVar = pbd->getSingleVar()) {
auto originalVar = singleVar->getOriginalWrappedProperty();
if (originalVar &&
originalVar->isPropertyMemberwiseInitializedWithWrappedType()) {
injectIntoWrapper = true;
}
}
SGFContext C = (injectIntoWrapper ? SGFContext() : SGFContext(init));
RValue result = SGF.emitApplyOfStoredPropertyInitializer(
pbd->getExecutableInit(i),
pbd->getAnchoringVarDecl(i),
subs, substType, origType, C);
// need to store result into the init if its in context
// If we have the backing storage for a property with an attached
// property wrapper initialized with `=`, inject the value into an
// instance of the wrapper.
if (injectIntoWrapper) {
auto *singleVar = pbd->getSingleVar();
result = maybeEmitPropertyWrapperInitFromValue(
SGF, pbd->getExecutableInit(i),
singleVar, subs, std::move(result));
}
if (!result.isInContext())
std::move(result).forwardInto(SGF, loc, init);
}
void SILGenFunction::emitMemberInitializers(DeclContext *dc,
VarDecl *selfDecl,
NominalTypeDecl *nominal) {
auto subs = getSubstitutionsForPropertyInitializer(dc, nominal);
for (auto member : nominal->getMembers()) {
// Find instance pattern binding declarations that have initializers.
if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
if (pbd->isStatic()) continue;
for (auto i : range(pbd->getNumPatternEntries())) {
auto init = pbd->getExecutableInit(i);
if (!init) continue;
auto *varPattern = pbd->getPattern(i);
// Cleanup after this initialization.
FullExpr scope(Cleanups, varPattern);
// Get the type of the initialization result, in terms
// of the constructor context's archetypes.
auto resultType = getInitializationTypeInContext(
pbd->getDeclContext(), dc, varPattern);
AbstractionPattern origType = resultType.first;
CanType substType = resultType.second;
// Figure out what we're initializing.
auto memberInit = emitMemberInit(*this, selfDecl, varPattern);
// This whole conversion thing is about eliminating the
// paired orig-to-subst subst-to-orig conversions that
// will happen if the storage is at a different abstraction
// level than the constructor. When emitApply() is used
// to call the stored property initializer, it naturally
// wants to convert the result back to the most substituted
// abstraction level. To undo this, we use a converting
// initialization and rely on the peephole that optimizes
// out the redundant conversion.
auto loweredResultTy = getLoweredType(origType, substType);
auto loweredSubstTy = getLoweredType(substType);
if (loweredResultTy != loweredSubstTy) {
Conversion conversion = Conversion::getSubstToOrig(
origType, substType,
loweredResultTy);
ConvertingInitialization convertingInit(conversion,
SGFContext(memberInit.get()));
emitAndStoreInitialValueInto(*this, varPattern, pbd, i, subs,
origType, substType, &convertingInit);
auto finalValue = convertingInit.finishEmission(
*this, varPattern, ManagedValue::forInContext());
if (!finalValue.isInContext())
finalValue.forwardInto(*this, varPattern, memberInit.get());
} else {
emitAndStoreInitialValueInto(*this, varPattern, pbd, i, subs,
origType, substType, memberInit.get());
}
}
}
}
}
void SILGenFunction::emitIVarInitializer(SILDeclRef ivarInitializer) {
auto cd = cast<ClassDecl>(ivarInitializer.getDecl());
RegularLocation loc(cd);
loc.markAutoGenerated();
// Emit 'self', then mark it uninitialized.
auto selfDecl = cd->getDestructor()->getImplicitSelfDecl();
SILType selfTy = getLoweredLoadableType(selfDecl->getType());
SILValue selfArg = F.begin()->createFunctionArgument(selfTy, selfDecl);
SILLocation PrologueLoc(selfDecl);
PrologueLoc.markAsPrologue();
// Hard-code self as argument number 1.
SILDebugVariable DbgVar(selfDecl->isLet(), 1);
B.createDebugValue(PrologueLoc, selfArg, DbgVar);
selfArg = B.createMarkUninitialized(selfDecl, selfArg,
MarkUninitializedInst::RootSelf);
assert(selfTy.hasReferenceSemantics() && "can't emit a value type ctor here");
VarLocs[selfDecl] = VarLoc::get(selfArg);
auto cleanupLoc = CleanupLocation::get(loc);
prepareEpilog(false, false, cleanupLoc);
// Emit the initializers.
emitMemberInitializers(cd, selfDecl, cd);
// Return 'self'.
B.createReturn(loc, selfArg);
emitEpilog(loc);
}