//===--- SILGenConstructor.cpp - SILGen for constructors ------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SILGenFunction.h"
#include "Initialization.h"
#include "LValue.h"
#include "RValue.h"
#include "Scope.h"
#include "swift/AST/AST.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/Basic/Defer.h"

using namespace swift;
using namespace Lowering;

static SILValue emitConstructorMetatypeArg(SILGenFunction &gen,
                                           ValueDecl *ctor) {
  // In addition to the declared arguments, the constructor implicitly takes
  // the metatype as its first argument, like a static function.
  Type metatype = ctor->getType()->castTo<AnyFunctionType>()->getInput();
  auto &AC = gen.getASTContext();
  auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(),
                               AC.getIdentifier("$metatype"), SourceLoc(),
                               AC.getIdentifier("$metatype"), metatype,
                               ctor->getDeclContext());
  gen.AllocatorMetatype = new (gen.F.getModule()) SILArgument(gen.F.begin(),
                                              gen.getLoweredType(metatype), VD);
  return gen.AllocatorMetatype;
}

static RValue emitImplicitValueConstructorArg(SILGenFunction &gen,
                                              SILLocation loc,
                                              CanType ty,
                                              DeclContext *DC) {
  // Restructure tuple arguments.
  if (CanTupleType tupleTy = dyn_cast<TupleType>(ty)) {
    RValue tuple(ty);
    for (auto fieldType : tupleTy.getElementTypes())
      tuple.addElement(emitImplicitValueConstructorArg(gen, loc, fieldType, DC));

    return tuple;
  } else {
    auto &AC = gen.getASTContext();
    auto VD = new (AC) ParamDecl(/*IsLet*/ true, SourceLoc(),
                                 AC.getIdentifier("$implicit_value"),
                                 SourceLoc(),
                                 AC.getIdentifier("$implicit_value"), ty, DC);
    SILValue arg = new (gen.F.getModule()) SILArgument(gen.F.begin(),
                                                       gen.getLoweredType(ty),
                                                       VD);
    return RValue(gen, loc, ty, gen.emitManagedRValueWithCleanup(arg));
  }
}

static void emitImplicitValueConstructor(SILGenFunction &gen,
                                         ConstructorDecl *ctor) {
  RegularLocation Loc(ctor);
  Loc.markAutoGenerated();
  // FIXME: Handle 'self' along with the other arguments.
  auto *TP = cast<TuplePattern>(ctor->getBodyParamPatterns()[1]);
  auto selfTyCan = ctor->getImplicitSelfDecl()->getType()->getInOutObjectType();
  SILType selfTy = gen.getLoweredType(selfTyCan);

  // Emit the indirect return argument, if any.
  SILValue resultSlot;
  if (selfTy.isAddressOnly(gen.SGM.M)) {
    auto &AC = gen.getASTContext();
    auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(),
                                 AC.getIdentifier("$return_value"),
                                 SourceLoc(),
                                 AC.getIdentifier("$return_value"), selfTyCan,
                                 ctor);
    resultSlot = new (gen.F.getModule()) SILArgument(gen.F.begin(), selfTy, VD);
  }

  // Emit the elementwise arguments.
  SmallVector<RValue, 4> elements;
  for (size_t i = 0, size = TP->getNumElements(); i < size; ++i) {
    auto *P = cast<TypedPattern>(TP->getElement(i).getPattern());

    elements.push_back(
      emitImplicitValueConstructorArg(gen, Loc,
                                      P->getType()->getCanonicalType(), ctor));
  }

  emitConstructorMetatypeArg(gen, ctor);

  auto *decl = selfTy.getStructOrBoundGenericStruct();
  assert(decl && "not a struct?!");

  // 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, gen.SGM.M);
      auto &fieldTL = gen.getTypeLowering(fieldTy);
      SILValue slot = gen.B.createStructElementAddr(Loc, resultSlot, field,
                                                    fieldTL.getLoweredType().getAddressType());
      InitializationPtr init(new KnownAddressInitialization(slot));

      // An initialized 'let' property has a single value specified by the
      // initializer - it doesn't come from an argument.
      if (!field->isStatic() && field->isLet() &&
          field->getParentInitializer()) {
        assert(field->getType()->isEqual(field->getParentInitializer()
                                         ->getType()) && "Checked by sema");

        // Cleanup after this initialization.
        FullExpr scope(gen.Cleanups, field->getParentPatternBinding());
        gen.emitRValue(field->getParentInitializer())
          .forwardInto(gen, init.get(), Loc);
        continue;
      }

      assert(elti != eltEnd && "number of args does not match number of fields");
      (void)eltEnd;
      std::move(*elti).forwardInto(gen, init.get(), Loc);
      ++elti;
    }
    gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
                       gen.emitEmptyTuple(Loc));
    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, gen.SGM.M);
    SILValue v;

    // An initialized 'let' property has a single value specified by the
    // initializer - it doesn't come from an argument.
    if (!field->isStatic() && field->isLet() && field->getParentInitializer()) {
      // Cleanup after this initialization.
      FullExpr scope(gen.Cleanups, field->getParentPatternBinding());
      v = gen.emitRValue(field->getParentInitializer())
             .forwardAsSingleStorageValue(gen, fieldTy, Loc);
    } else {
      assert(elti != eltEnd && "number of args does not match number of fields");
      (void)eltEnd;
      v = std::move(*elti).forwardAsSingleStorageValue(gen, fieldTy, Loc);
      ++elti;
    }

    eltValues.push_back(v);
  }

  SILValue selfValue = gen.B.createStruct(Loc, selfTy, eltValues);
  gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
                     selfValue);
  return;
}

static unsigned countSwiftArgs(ArrayRef<Pattern *> Patterns) {
  unsigned N = 0;
  for (auto p : Patterns)
      p->forEachVariable([&](VarDecl *) { ++N; });
  return N;
}

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(nullptr) ==
    ConstructorDecl::BodyInitKind::Delegating;

  // Get the 'self' decl and type.
  VarDecl *selfDecl = ctor->getImplicitSelfDecl();
  auto &lowering = getTypeLowering(selfDecl->getType()->getInOutObjectType());
  SILType selfTy = lowering.getLoweredType();
  (void)selfTy;
  assert(!selfTy.getClassOrBoundGenericClass()
         && "can't emit a class ctor here");

  // Self is a curried argument and thus comes last.
  unsigned N = countSwiftArgs(ctor->getBodyParamPatterns()[1]) + 1;
  // Allocate the local variable for 'self'.
  emitLocalVariableWithCleanup(selfDecl, false, N)->finishInitialization(*this);
  
  // Mark self as being uninitialized so that DI knows where it is and how to
  // check for it.
  SILValue selfLV;
  {
    auto &SelfVarLoc = VarLocs[selfDecl];
    auto MUIKind =  isDelegating ? MarkUninitializedInst::DelegatingSelf
                                 : MarkUninitializedInst::RootSelf;
    selfLV = B.createMarkUninitialized(selfDecl, SelfVarLoc.value, MUIKind);
    SelfVarLoc.value = selfLV;
  }
  
  // Emit the prolog.
  emitProlog(ctor->getBodyParamPatterns()[1], ctor->getResultType(), ctor);
  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(Type(), ctor->isBodyThrowing(), CleanupLocation(ctor));

  // If the constructor can fail, set up an alternative epilog for constructor
  // failure.
  SILBasicBlock *failureExitBB = nullptr;
  SILArgument *failureExitArg = nullptr;
  auto &resultLowering = getTypeLowering(ctor->getResultType());

  if (ctor->getFailability() != OTK_None) {
    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.
    SavedInsertionPoint savedIP(*this, failureBB, FunctionSection::Postmatter);
    failureExitBB = createBasicBlock();
    Cleanups.emitCleanupsForReturn(ctor);
    // Return nil.
    if (lowering.isAddressOnly()) {
      // Inject 'nil' into the indirect return.
      B.createInjectEnumAddr(ctor, IndirectReturnAddress,
                   getASTContext().getOptionalNoneDecl(ctor->getFailability()));
      B.createBranch(ctor, failureExitBB);

      B.setInsertionPoint(failureExitBB);
      B.createReturn(ctor, emitEmptyTuple(ctor));
    } else {
      // Pass 'nil' as the return value to the exit BB.
      failureExitArg = new (F.getModule())
        SILArgument(failureExitBB, resultLowering.getLoweredType());
      SILValue nilResult = B.createEnum(ctor, {},
                    getASTContext().getOptionalNoneDecl(ctor->getFailability()),
                    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 nominal = ctor->getDeclContext()->getDeclaredTypeInContext()
                     ->getNominalOrBoundGenericNominal();
    emitMemberInitializers(selfDecl, nominal);
  }

  emitProfilerIncrement(ctor->getBody());
  // Emit the constructor body.
  emitStmt(ctor->getBody());

  
  // 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;
  {
    SavedInsertionPoint savedIP(*this, ReturnDest.getBlock());
    assert(B.getInsertionBB()->empty() && "Epilog already set up?");
    
    auto cleanupLoc = CleanupLocation::get(ctor);
    
    if (!lowering.isAddressOnly()) {
      // Otherwise, load and return the final 'self' value.
      selfValue = B.createLoad(cleanupLoc, selfLV);
      
      // Emit a retain of the loaded value, since we return it +1.
      lowering.emitRetainValue(B, cleanupLoc, selfValue);
      
      // Inject the self value into an optional if the constructor is failable.
      if (ctor->getFailability() != OTK_None) {
        selfValue = B.createEnum(ctor, selfValue,
                                 getASTContext().getOptionalSomeDecl(ctor->getFailability()),
                                 getLoweredLoadableType(ctor->getResultType()));
      }
    } else {
      // If 'self' is address-only, copy 'self' into the indirect return slot.
      assert(IndirectReturnAddress &&
             "no indirect return for address-only ctor?!");
      
      // Get the address to which to store the result.
      SILValue returnAddress;
      switch (ctor->getFailability()) {
      // For non-failable initializers, store to the return address directly.
      case OTK_None:
        returnAddress = IndirectReturnAddress;
        break;
      // If this is a failable initializer, project out the payload.
      case OTK_Optional:
      case OTK_ImplicitlyUnwrappedOptional:
        returnAddress = B.createInitEnumDataAddr(ctor, IndirectReturnAddress,
                 getASTContext().getOptionalSomeDecl(ctor->getFailability()),
                                                 selfLV.getType());
        break;
      }
      
      // 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->getFailability() != OTK_None) {
        // Inject the 'Some' tag.
        B.createInjectEnumAddr(ctor, IndirectReturnAddress,
                               getASTContext().getOptionalSomeDecl(ctor->getFailability()));
      }
    }
  }
  
  // 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 (!selfValue)
        selfValue = emitEmptyTuple(ctor);
      
      B.createReturn(returnLoc, selfValue);
    } else {
      if (selfValue)
        B.createBranch(returnLoc, failureExitBB, selfValue);
      else
        B.createBranch(returnLoc, failureExitBB);
    }
  }
}

static void boxIndirectEnumPayload(SILGenFunction &gen,
                                   ManagedValue &payload,
                                   SILLocation loc,
                                   EnumElementDecl *element) {
  // If the payload is indirect, we'll need to box it.
  if (payload && (element->isIndirect() ||
                  element->getParentEnum()->isIndirect())) {
    auto box = gen.B.createAllocBox(loc, payload.getType());
    payload.forwardInto(gen, loc, box->getAddressResult());
    payload = gen.emitManagedRValueWithCleanup(box);
  }
}

static void emitAddressOnlyEnumConstructor(SILGenFunction &gen,
                                           SILType enumTy,
                                           EnumElementDecl *element) {
  RegularLocation Loc(element);
  CleanupLocation CleanupLoc(element);
  Loc.markAutoGenerated();

  // Emit the indirect return slot.
  auto &AC = gen.getASTContext();
  auto VD = new (AC) ParamDecl(/*IsLet*/ false, SourceLoc(),
                               AC.getIdentifier("$return_value"),
                               SourceLoc(),
                               AC.getIdentifier("$return_value"),
                               enumTy.getSwiftType(),
                               element->getDeclContext());
  SILValue resultSlot
    = new (gen.F.getModule()) SILArgument(gen.F.begin(), enumTy, VD);

  Scope scope(gen.Cleanups, CleanupLoc);

  // Emit the exploded constructor argument.
  ManagedValue argValue;
  if (element->hasArgumentType()) {
    RValue arg = emitImplicitValueConstructorArg
      (gen, Loc, element->getArgumentType()->getCanonicalType(),
       element->getDeclContext());
    argValue = std::move(arg).getAsSingleValue(gen, Loc);
  }
  emitConstructorMetatypeArg(gen, element);

  boxIndirectEnumPayload(gen, argValue, Loc, element);

  // Store the data, if any.
  if (argValue) {
    SILValue resultData = gen.B.createInitEnumDataAddr(element, resultSlot,
      element, argValue.getType().getAddressType());
    argValue.forwardInto(gen, element, resultData);
  }

  // Apply the tag.
  gen.B.createInjectEnumAddr(Loc, resultSlot, element);
  scope.pop();
  gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
                     gen.emitEmptyTuple(element));
}

static void emitLoadableEnumConstructor(SILGenFunction &gen, SILType enumTy,
                                        EnumElementDecl *element) {
  RegularLocation Loc(element);
  CleanupLocation CleanupLoc(element);
  Loc.markAutoGenerated();

  Scope scope(gen.Cleanups, CleanupLoc);

  // Emit the exploded constructor argument.
  ManagedValue payload;
  if (element->hasArgumentType()) {
    RValue arg = emitImplicitValueConstructorArg
      (gen, Loc,
       element->getArgumentType()->getCanonicalType(),
       element->getDeclContext());
    payload = std::move(arg).getAsSingleValue(gen, Loc);
  }

  emitConstructorMetatypeArg(gen, element);

  boxIndirectEnumPayload(gen, payload, Loc, element);

  // Create and return the enum value.
  SILValue argValue;
  if (payload)
    argValue = payload.forward(gen);
  SILValue result = gen.B.createEnum(Loc, argValue, element, enumTy);
  scope.pop();
  gen.B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc), result);
}

void SILGenFunction::emitEnumConstructor(EnumElementDecl *element) {
  Type enumTy = element->getType()->getAs<AnyFunctionType>()->getResult();
  if (element->hasArgumentType())
    enumTy = enumTy->getAs<AnyFunctionType>()->getResult();
  auto &enumTI = getTypeLowering(enumTy);

  if (enumTI.isAddressOnly()) {
    return emitAddressOnlyEnumConstructor(*this, enumTI.getLoweredType(),
                                           element);
  }
  return emitLoadableEnumConstructor(*this, enumTI.getLoweredType(),
                                      element);
}

bool Lowering::usesObjCAllocator(ClassDecl *theClass) {
  while (true) {
    // If the root class was implemented in Objective-C, use Objective-C's
    // allocation methods because they may have been overridden.
    if (!theClass->hasSuperclass())
      return theClass->hasClangNode();

    theClass = theClass->getSuperclass()->getClassOrBoundGenericClass();
  }
}

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->getBodyParamPatterns()[1], 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 selfTypeContext = ctor->getDeclContext()->getDeclaredTypeInContext();
  auto selfClassDecl =
    cast<ClassDecl>(selfTypeContext->getNominalOrBoundGenericNominal());

  SILValue selfValue;

  // Allocate the 'self' value.
  bool useObjCAllocation = usesObjCAllocator(selfClassDecl);

  if (ctor->isConvenienceInit() || ctor->hasClangNode()) {
    // For a convenience initializer or an initializer synthesized
    // for an Objective-C class, 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 {
    // For a designated initializer, we know that the static type being
    // allocated is the type of the class that defines the designated
    // initializer.
    selfValue = B.createAllocRef(Loc, selfTy, useObjCAllocation, false);
  }
  args.push_back(selfValue);

  // Call the initializer. Always use the Swift entry point, which will be a
  // bridging thunk if we're calling ObjC.
  SILDeclRef initConstant =
    SILDeclRef(ctor,
               SILDeclRef::Kind::Initializer,
               SILDeclRef::ConstructAtBestResilienceExpansion,
               SILDeclRef::ConstructAtNaturalUncurryLevel,
               /*isObjC=*/false);

  ManagedValue initVal;
  SILType initTy;

  ArrayRef<Substitution> subs;
  // Call the initializer.
  ArrayRef<Substitution> forwardingSubs;
  if (auto *genericParamList = ctor->getGenericParamsOfContext())
    forwardingSubs =
        genericParamList->getForwardingSubstitutions(getASTContext());
  std::tie(initVal, initTy, subs)
    = emitSiblingMethodRef(Loc, selfValue, initConstant, forwardingSubs);

  SILValue initedSelfValue = emitApplyWithRethrow(Loc, initVal.forward(*this),
                                                  initTy, subs, args);

  // Return the initialized 'self'.
  B.createReturn(ImplicitReturnLocation::getImplicitReturnLoc(Loc),
                 initedSelfValue);
}

void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
  MagicFunctionName = SILGenModule::getMagicFunctionName(ctor);

  assert(ctor->getBody() && "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(nullptr) ==
      ConstructorDecl::BodyInitKind::Delegating;
  }

  // FIXME: The (potentially partially initialized) value here would need to be
  // cleaned up on a constructor failure unwinding, if we were to support
  // failing before total initialization.

  // 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 selfTypeContext = ctor->getDeclContext()->getDeclaredTypeInContext();
  auto selfClassDecl =
    cast<ClassDecl>(selfTypeContext->getNominalOrBoundGenericNominal());
  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)
    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, false)->finishInitialization(*this);

    auto &SelfVarLoc = VarLocs[selfDecl];
    SelfVarLoc.value = B.createMarkUninitialized(selfDecl,
                                                 SelfVarLoc.value, MUKind);
  }

  // Emit the prolog for the non-self arguments.
  // FIXME: Handle self along with the other body patterns.
  emitProlog(ctor->getBodyParamPatterns()[1],
             TupleType::getEmpty(F.getASTContext()), ctor);

  SILType selfTy = getLoweredLoadableType(selfDecl->getType());
  SILValue selfArg = new (SGM.M) SILArgument(F.begin(), selfTy, selfDecl);

  if (!NeedsBoxForSelf) {
    SILLocation PrologueLoc(selfDecl);
    PrologueLoc.markAsPrologue();
    B.createDebugValue(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.createStore(prologueLoc, selfArg, VarLocs[selfDecl].value);
    } else {
      selfArg = B.createMarkUninitialized(selfDecl, selfArg, MUKind);
      VarLocs[selfDecl] = VarLoc::get(selfArg);
      enterDestroyCleanup(VarLocs[selfDecl].value);
    }
  }

  // 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(Type(), ctor->isBodyThrowing(),
                CleanupLocation::get(endOfInitLoc));

  // If the constructor can fail, set up an alternative epilog for constructor
  // failure.
  SILBasicBlock *failureExitBB = nullptr;
  SILArgument *failureExitArg = nullptr;
  auto &resultLowering = getTypeLowering(ctor->getResultType());

  if (ctor->getFailability() != OTK_None) {
    SILBasicBlock *failureBB = createBasicBlock(FunctionSection::Postmatter);

    RegularLocation loc(ctor);
    loc.markAutoGenerated();

    // On failure, we'll clean up everything and return nil instead.
    SavedInsertionPoint savedIP(*this, failureBB, FunctionSection::Postmatter);

    failureExitBB = createBasicBlock();
    failureExitArg = new (F.getModule())
      SILArgument(failureExitBB, resultLowering.getLoweredType());

    Cleanups.emitCleanupsForReturn(ctor);
    SILValue nilResult = B.createEnum(loc, {},
                    getASTContext().getOptionalNoneDecl(ctor->getFailability()),
                    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(selfDecl, selfClassDecl);
  }

  emitProfilerIncrement(ctor->getBody());
  // Emit the constructor body.
  emitStmt(ctor->getBody());

  
  // 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.
  {
    SavedInsertionPoint savedIP(*this, ReturnDest.getBlock());
    assert(B.getInsertionBB()->empty() && "Epilog already set up?");
    auto cleanupLoc = CleanupLocation(ctor);

    // If we're using a box for self, reload the value at the end of the init
    // method.
    if (NeedsBoxForSelf) {
      // Emit the call to super.init() right before exiting from the initializer.
      if (Expr *SI = ctor->getSuperInitCall())
        emitRValue(SI);
      
      selfArg = B.createLoad(cleanupLoc, VarLocs[selfDecl].value);
    }
    
    // We have to do a retain because we are returning the pointer +1.
    B.emitRetainValueOperation(cleanupLoc, selfArg);

    // Inject the self value into an optional if the constructor is failable.
    if (ctor->getFailability() != OTK_None) {
      RegularLocation loc(ctor);
      loc.markAutoGenerated();
      selfArg = B.createEnum(loc, selfArg,
                 getASTContext().getOptionalSomeDecl(ctor->getFailability()),
                             getLoweredLoadableType(ctor->getResultType()));
    }
  }
  
  // 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)
      B.createBranch(returnLoc, failureExitBB, selfArg);
    else
      B.createReturn(returnLoc, selfArg);
  }
}


/// Emit a member initialization for the members described in the
/// given pattern from the given source value.
static void emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl,
                           Pattern *pattern, RValue &&src) {
  switch (pattern->getKind()) {
  case PatternKind::Paren:
    return emitMemberInit(SGF, selfDecl,
                          cast<ParenPattern>(pattern)->getSubPattern(),
                          std::move(src));

  case PatternKind::Tuple: {
    auto tuple = cast<TuplePattern>(pattern);
    auto fields = tuple->getElements();

    SmallVector<RValue, 4> elements;
    std::move(src).extractElements(elements);
    for (unsigned i = 0, n = fields.size(); i != n; ++i) {
      emitMemberInit(SGF, selfDecl, fields[i].getPattern(),
                     std::move(elements[i]));
    }
    break;
  }

  case PatternKind::Named: {
    auto named = cast<NamedPattern>(pattern);
    // Form the lvalue referencing this member.
    WritebackScope scope(SGF);
    SILLocation loc = pattern;
    ManagedValue self;
    CanType selfFormalType = selfDecl->getType()
        ->getInOutObjectType()->getCanonicalType();
    if (selfFormalType->hasReferenceSemantics())
      self = SGF.emitRValueForDecl(loc, selfDecl, selfDecl->getType(),
                                   AccessSemantics::DirectToStorage,
                                   SGFContext::AllowImmediatePlusZero);
    else
      self = SGF.emitLValueForDecl(loc, selfDecl, src.getType(),
                                   AccessKind::Write,
                                   AccessSemantics::DirectToStorage);

    LValue memberRef =
      SGF.emitPropertyLValue(loc, self, selfFormalType, named->getDecl(),
                             AccessKind::Write,
                             AccessSemantics::DirectToStorage);

    // Assign to it.
    SGF.emitAssignToLValue(loc, std::move(src), std::move(memberRef));
    return;
  }

  case PatternKind::Any:
    return;

  case PatternKind::Typed:
    return emitMemberInit(SGF, selfDecl,
                          cast<TypedPattern>(pattern)->getSubPattern(),
                          std::move(src));

  case PatternKind::Var:
    return emitMemberInit(SGF, selfDecl,
                          cast<VarPattern>(pattern)->getSubPattern(),
                          std::move(src));

#define PATTERN(Name, Parent)
#define REFUTABLE_PATTERN(Name, Parent) case PatternKind::Name:
#include "swift/AST/PatternNodes.def"
    llvm_unreachable("Refutable pattern in pattern binding");
  }
}

void SILGenFunction::emitMemberInitializers(VarDecl *selfDecl,
                                            NominalTypeDecl *nominal) {
  for (auto member : nominal->getMembers()) {
    // Find pattern binding declarations that have initializers.
    auto pbd = dyn_cast<PatternBindingDecl>(member);
    if (!pbd || pbd->isStatic()) continue;

    for (auto entry : pbd->getPatternList()) {
      auto init = entry.getInit();
      if (!init) continue;

      // Cleanup after this initialization.
      FullExpr scope(Cleanups, entry.getPattern());
      emitMemberInit(*this, selfDecl, entry.getPattern(), emitRValue(init));
    }
  }
}

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 = new (SGM.M) SILArgument(F.begin(), selfTy, selfDecl);
  SILLocation PrologueLoc(selfDecl);
  PrologueLoc.markAsPrologue();
  B.createDebugValue(PrologueLoc, selfArg);
  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(TupleType::getEmpty(getASTContext()), false, cleanupLoc);

  // Emit the initializers.
  emitMemberInitializers(cd->getDestructor()->getImplicitSelfDecl(), cd);

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

  emitEpilog(loc);
}
