Files
swift-mirror/lib/Sema/CodeSynthesis.cpp

679 lines
26 KiB
C++

//===--- CodeSynthesis.cpp - Type Checking for Declarations ---------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for declarations.
//
//===----------------------------------------------------------------------===//
#include "CodeSynthesis.h"
#include "ConstraintSystem.h"
#include "TypeChecker.h"
#include "TypeCheckObjC.h"
#include "TypeCheckType.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Availability.h"
#include "swift/AST/Expr.h"
#include "swift/AST/GenericEnvironment.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Defer.h"
#include "swift/ClangImporter/ClangModule.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
using namespace swift;
const bool IsImplicit = true;
Expr *swift::buildSelfReference(VarDecl *selfDecl,
SelfAccessorKind selfAccessorKind,
bool isLValue,
ASTContext &ctx) {
switch (selfAccessorKind) {
case SelfAccessorKind::Peer:
return new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), IsImplicit,
AccessSemantics::Ordinary,
isLValue
? LValueType::get(selfDecl->getType())
: selfDecl->getType());
case SelfAccessorKind::Super:
assert(!isLValue);
return new (ctx) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit,
selfDecl->getType()->getSuperclass());
}
llvm_unreachable("bad self access kind");
}
/// Build an expression that evaluates the specified parameter list as a tuple
/// or paren expr, suitable for use in an apply expr.
Expr *swift::buildArgumentForwardingExpr(ArrayRef<ParamDecl*> params,
ASTContext &ctx) {
SmallVector<Identifier, 4> labels;
SmallVector<SourceLoc, 4> labelLocs;
SmallVector<Expr *, 4> args;
SmallVector<AnyFunctionType::Param, 4> elts;
for (auto param : params) {
auto type = param->getType();
elts.push_back(param->toFunctionParam(type));
Expr *ref = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true);
ref->setType(param->isInOut() ? LValueType::get(type) : type);
if (param->isInOut()) {
ref = new (ctx) InOutExpr(SourceLoc(), ref, type, /*isImplicit=*/true);
} else if (param->isVariadic()) {
ref = new (ctx) VarargExpansionExpr(ref, /*implicit*/ true);
ref->setType(type);
}
args.push_back(ref);
labels.push_back(param->getArgumentName());
labelLocs.push_back(SourceLoc());
}
Expr *argExpr;
if (args.size() == 1 &&
labels[0].empty() &&
!isa<VarargExpansionExpr>(args[0])) {
argExpr = new (ctx) ParenExpr(SourceLoc(), args[0], SourceLoc(),
/*hasTrailingClosure=*/false);
argExpr->setImplicit();
} else {
argExpr = TupleExpr::create(ctx, SourceLoc(), args, labels, labelLocs,
SourceLoc(), false, IsImplicit);
}
auto argTy = AnyFunctionType::composeInput(ctx, elts, /*canonical*/false);
argExpr->setType(argTy);
return argExpr;
}
static void maybeAddMemberwiseDefaultArg(ParamDecl *arg, VarDecl *var,
SmallVectorImpl<DefaultArgumentInitializer *> &defaultInits,
unsigned paramSize, ASTContext &ctx) {
// First and foremost, if this is a constant don't bother.
if (var->isLet())
return;
// We can only provide default values for patterns binding a single variable.
// i.e. var (a, b) = getSomeTuple() is not allowed.
if (!var->getParentPattern()->getSingleVar())
return;
// Whether we have explicit initialization.
bool isExplicitlyInitialized = false;
if (auto pbd = var->getParentPatternBinding()) {
auto &entry = pbd->getPatternEntryForVarDecl(var);
isExplicitlyInitialized =
entry.isInitialized() && entry.getEqualLoc().isValid();
}
// Whether we can default-initialize this property.
auto binding = var->getParentPatternBinding();
bool isDefaultInitializable =
var->getAttrs().hasAttribute<LazyAttr>() ||
(binding && binding->isDefaultInitializable());
// If this is neither explicitly initialized nor
// default-initializable, don't add anything.
if (!isExplicitlyInitialized && !isDefaultInitializable)
return;
// We can add a default value now.
// Give this some bogus context right now, we'll fix it after making
// the constructor.
auto *initDC = new (ctx) DefaultArgumentInitializer(
arg->getDeclContext(), paramSize);
defaultInits.push_back(initDC);
// If the variable has a type T? and no initial value, return a nil literal
// default arg. All lazy variables return a nil literal as well. *Note* that
// the type will always be a sugared T? because we don't default init an
// explicit Optional<T>.
bool isNilInitialized =
var->getAttrs().hasAttribute<LazyAttr>() ||
(!isExplicitlyInitialized && isDefaultInitializable &&
var->getValueInterfaceType()->getAnyNominal() == ctx.getOptionalDecl() &&
!var->getAttachedPropertyWrapperTypeInfo(0).defaultInit);
if (isNilInitialized) {
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
return;
}
// If there's a backing storage property, the memberwise initializer
// will be in terms of that.
VarDecl *backingStorageVar = var->getPropertyWrapperBackingProperty();
// Set the default value to the variable. When we emit this in silgen
// we're going to call the variable's initializer expression.
arg->setStoredProperty(backingStorageVar ? backingStorageVar : var);
arg->setDefaultArgumentKind(DefaultArgumentKind::StoredProperty);
}
/// Create an implicit struct or class constructor.
///
/// \param decl The struct or class for which a constructor will be created.
/// \param ICK The kind of implicit constructor to create.
///
/// \returns The newly-created constructor, which has already been type-checked
/// (but has not been added to the containing struct or class).
ConstructorDecl *swift::createImplicitConstructor(TypeChecker &tc,
NominalTypeDecl *decl,
ImplicitConstructorKind ICK) {
assert(!decl->hasClangNode());
ASTContext &ctx = tc.Context;
SourceLoc Loc = decl->getLoc();
auto accessLevel = AccessLevel::Internal;
// Determine the parameter type of the implicit constructor.
SmallVector<ParamDecl*, 8> params;
SmallVector<DefaultArgumentInitializer *, 8> defaultInits;
if (ICK == ImplicitConstructorKind::Memberwise) {
assert(isa<StructDecl>(decl) && "Only struct have memberwise constructor");
for (auto member : decl->getMembers()) {
auto var = dyn_cast<VarDecl>(member);
if (!var)
continue;
if (!var->isMemberwiseInitialized(/*preferDeclaredProperties=*/true))
continue;
accessLevel = std::min(accessLevel, var->getFormalAccess());
tc.validateDecl(var);
auto varInterfaceType = var->getValueInterfaceType();
if (var->getAttrs().hasAttribute<LazyAttr>()) {
// If var is a lazy property, its value is provided for the underlying
// storage. We thus take an optional of the property's type. We only
// need to do this because the implicit initializer is added before all
// the properties are type checked. Perhaps init() synth should be
// moved later.
varInterfaceType = OptionalType::get(varInterfaceType);
} else if (Type backingPropertyType =
var->getPropertyWrapperBackingPropertyType()) {
// For a property that has a wrapper, writing the initializer
// with an '=' implies that the memberwise initializer should also
// accept a value of the original property type. Otherwise, the
// memberwise initializer will be in terms of the backing storage
// type.
if (!var->isPropertyMemberwiseInitializedWithWrappedType()) {
varInterfaceType = backingPropertyType;
}
}
// Create the parameter.
auto *arg = new (ctx)
ParamDecl(ParamDecl::Specifier::Default, SourceLoc(), Loc,
var->getName(), Loc, var->getName(), decl);
arg->setInterfaceType(varInterfaceType);
arg->setImplicit();
maybeAddMemberwiseDefaultArg(arg, var, defaultInits, params.size(), ctx);
params.push_back(arg);
}
}
auto paramList = ParameterList::create(ctx, params);
// Create the constructor.
DeclName name(ctx, DeclBaseName::createConstructor(), paramList);
auto *ctor =
new (ctx) ConstructorDecl(name, Loc,
OTK_None, /*FailabilityLoc=*/SourceLoc(),
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
paramList, /*GenericParams=*/nullptr, decl);
// Mark implicit.
ctor->setImplicit();
ctor->setAccess(accessLevel);
if (ICK == ImplicitConstructorKind::Memberwise) {
ctor->setIsMemberwiseInitializer();
// Fix default argument init contexts now that we have a constructor.
for (auto initDC : defaultInits) {
initDC->changeFunction(ctor, paramList);
}
}
// If we are defining a default initializer for a class that has a superclass,
// it overrides the default initializer of its superclass. Add an implicit
// 'override' attribute.
if (auto classDecl = dyn_cast<ClassDecl>(decl)) {
if (classDecl->getSuperclass())
ctor->getAttrs().add(new (ctx) OverrideAttr(/*IsImplicit=*/true));
}
return ctor;
}
/// Create a stub body that emits a fatal error message.
static std::pair<BraceStmt *, bool>
synthesizeStubBody(AbstractFunctionDecl *fn, void *) {
auto *ctor = cast<ConstructorDecl>(fn);
auto &ctx = ctor->getASTContext();
auto unimplementedInitDecl = ctx.getUnimplementedInitializer();
auto classDecl = ctor->getDeclContext()->getSelfClassDecl();
if (!unimplementedInitDecl) {
ctx.Diags.diagnose(classDecl->getLoc(),
diag::missing_unimplemented_init_runtime);
return { nullptr, true };
}
auto *staticStringDecl = ctx.getStaticStringDecl();
auto staticStringType = staticStringDecl->getDeclaredType();
auto staticStringInit = ctx.getStringBuiltinInitDecl(staticStringDecl);
auto *uintDecl = ctx.getUIntDecl();
auto uintType = uintDecl->getDeclaredType();
auto uintInit = ctx.getIntBuiltinInitDecl(uintDecl);
// Create a call to Swift._unimplementedInitializer
auto loc = classDecl->getLoc();
Expr *ref = new (ctx) DeclRefExpr(unimplementedInitDecl,
DeclNameLoc(loc),
/*Implicit=*/true);
ref->setType(unimplementedInitDecl->getInterfaceType()
->removeArgumentLabels(1));
llvm::SmallString<64> buffer;
StringRef fullClassName = ctx.AllocateCopy(
(classDecl->getModuleContext()->getName().str() +
"." +
classDecl->getName().str()).toStringRef(buffer));
auto *className = new (ctx) StringLiteralExpr(fullClassName, loc,
/*Implicit=*/true);
className->setBuiltinInitializer(staticStringInit);
assert(isa<ConstructorDecl>(className->getBuiltinInitializer().getDecl()));
className->setType(staticStringType);
auto *initName = new (ctx) MagicIdentifierLiteralExpr(
MagicIdentifierLiteralExpr::Function, loc, /*Implicit=*/true);
initName->setType(staticStringType);
initName->setBuiltinInitializer(staticStringInit);
auto *file = new (ctx) MagicIdentifierLiteralExpr(
MagicIdentifierLiteralExpr::File, loc, /*Implicit=*/true);
file->setType(staticStringType);
file->setBuiltinInitializer(staticStringInit);
auto *line = new (ctx) MagicIdentifierLiteralExpr(
MagicIdentifierLiteralExpr::Line, loc, /*Implicit=*/true);
line->setType(uintType);
line->setBuiltinInitializer(uintInit);
auto *column = new (ctx) MagicIdentifierLiteralExpr(
MagicIdentifierLiteralExpr::Column, loc, /*Implicit=*/true);
column->setType(uintType);
column->setBuiltinInitializer(uintInit);
auto *call = CallExpr::createImplicit(
ctx, ref, { className, initName, file, line, column }, {});
call->setType(ctx.getNeverType());
call->setThrows(false);
SmallVector<ASTNode, 2> stmts;
stmts.push_back(call);
stmts.push_back(new (ctx) ReturnStmt(SourceLoc(), /*Result=*/nullptr));
return { BraceStmt::create(ctx, SourceLoc(), stmts, SourceLoc(),
/*implicit=*/true),
/*isTypeChecked=*/true };
}
static std::tuple<GenericEnvironment *, GenericParamList *, SubstitutionMap>
configureGenericDesignatedInitOverride(ASTContext &ctx,
ClassDecl *classDecl,
Type superclassTy,
ConstructorDecl *superclassCtor) {
auto *superclassDecl = superclassTy->getAnyNominal();
auto *moduleDecl = classDecl->getParentModule();
auto subMap = superclassTy->getContextSubstitutionMap(
moduleDecl, superclassDecl);
GenericEnvironment *genericEnv;
// Inheriting initializers that have their own generic parameters
auto *genericParams = superclassCtor->getGenericParams();
if (genericParams) {
SmallVector<GenericTypeParamDecl *, 4> newParams;
// First, clone the superclass constructor's generic parameter list,
// but change the depth of the generic parameters to be one greater
// than the depth of the subclass.
unsigned depth = 0;
if (auto *genericSig = classDecl->getGenericSignature())
depth = genericSig->getGenericParams().back()->getDepth() + 1;
for (auto *param : genericParams->getParams()) {
auto *newParam = new (ctx) GenericTypeParamDecl(classDecl,
param->getName(),
SourceLoc(),
depth,
param->getIndex());
newParams.push_back(newParam);
}
// We don't have to clone the requirements, because they're not
// used for anything.
genericParams = GenericParamList::create(ctx,
SourceLoc(),
newParams,
SourceLoc(),
ArrayRef<RequirementRepr>(),
SourceLoc());
// Build a generic signature for the derived class initializer.
GenericSignatureBuilder builder(ctx);
builder.addGenericSignature(classDecl->getGenericSignature());
// Add the generic parameters.
for (auto *newParam : newParams)
builder.addGenericParameter(newParam);
auto source =
GenericSignatureBuilder::FloatingRequirementSource::forAbstract();
auto *superclassSig = superclassCtor->getGenericSignature();
unsigned superclassDepth = 0;
if (auto *genericSig = superclassDecl->getGenericSignature())
superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1;
// We're going to be substituting the requirements of the base class
// initializer to form the requirements of the derived class initializer.
auto substFn = [&](SubstitutableType *type) -> Type {
auto *gp = cast<GenericTypeParamType>(type);
if (gp->getDepth() < superclassDepth)
return Type(gp).subst(subMap);
return CanGenericTypeParamType::get(
gp->getDepth() - superclassDepth + depth,
gp->getIndex(),
ctx);
};
auto lookupConformanceFn =
[&](CanType depTy, Type substTy, ProtocolDecl *proto)
-> Optional<ProtocolConformanceRef> {
if (auto conf = subMap.lookupConformance(depTy, proto))
return conf;
return ProtocolConformanceRef(proto);
};
for (auto reqt : superclassSig->getRequirements())
if (auto substReqt = reqt.subst(substFn, lookupConformanceFn))
builder.addRequirement(*substReqt, source, nullptr);
// Now form the substitution map that will be used to remap parameter
// types.
subMap = SubstitutionMap::get(superclassSig,
substFn, lookupConformanceFn);
auto *genericSig = std::move(builder).computeGenericSignature(SourceLoc());
genericEnv = genericSig->createGenericEnvironment();
} else {
genericEnv = classDecl->getGenericEnvironment();
}
return std::make_tuple(genericEnv, genericParams, subMap);
}
static void
configureInheritedDesignatedInitAttributes(TypeChecker &tc,
ClassDecl *classDecl,
ConstructorDecl *ctor,
ConstructorDecl *superclassCtor) {
assert(ctor->getDeclContext() == classDecl);
auto &ctx = tc.Context;
AccessLevel access = classDecl->getFormalAccess();
access = std::max(access, AccessLevel::Internal);
access = std::min(access, superclassCtor->getFormalAccess());
ctor->setAccess(access);
AccessScope superclassInliningAccessScope =
superclassCtor->getFormalAccessScope(/*useDC*/nullptr,
/*usableFromInlineAsPublic=*/true);
if (superclassInliningAccessScope.isPublic()) {
if (superclassCtor->getAttrs().hasAttribute<InlinableAttr>()) {
// Inherit the @inlinable attribute.
auto *clonedAttr = new (ctx) InlinableAttr(/*implicit=*/true);
ctor->getAttrs().add(clonedAttr);
} else if (access == AccessLevel::Internal && !superclassCtor->isDynamic()){
// Inherit the @usableFromInline attribute.
auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true);
ctor->getAttrs().add(clonedAttr);
}
}
// Inherit the @discardableResult attribute.
if (superclassCtor->getAttrs().hasAttribute<DiscardableResultAttr>()) {
auto *clonedAttr = new (ctx) DiscardableResultAttr(/*implicit=*/true);
ctor->getAttrs().add(clonedAttr);
}
// If the superclass has its own availability, make sure the synthesized
// constructor is only as available as its superclass's constructor.
if (superclassCtor->getAttrs().hasAttribute<AvailableAttr>()) {
SmallVector<Decl *, 2> asAvailableAs;
// We don't have to look at enclosing contexts of the superclass constructor,
// because designated initializers must always be defined in the superclass
// body, and we already enforce that a superclass is at least as available as
// a subclass.
asAvailableAs.push_back(superclassCtor);
Decl *parentDecl = classDecl;
while (parentDecl != nullptr) {
asAvailableAs.push_back(parentDecl);
parentDecl = parentDecl->getDeclContext()->getAsDecl();
}
AvailabilityInference::applyInferredAvailableAttrs(
ctor, asAvailableAs, ctx);
}
// Wire up the overrides.
ctor->setOverriddenDecl(superclassCtor);
if (superclassCtor->isRequired())
ctor->getAttrs().add(new (ctx) RequiredAttr(/*IsImplicit=*/false));
else
ctor->getAttrs().add(new (ctx) OverrideAttr(/*IsImplicit=*/false));
// If the superclass constructor is @objc but the subclass constructor is
// not representable in Objective-C, add @nonobjc implicitly.
Optional<ForeignErrorConvention> errorConvention;
if (superclassCtor->isObjC() &&
!isRepresentableInObjC(ctor, ObjCReason::MemberOfObjCSubclass,
errorConvention))
ctor->getAttrs().add(new (ctx) NonObjCAttr(/*isImplicit=*/true));
}
static std::pair<BraceStmt *, bool>
synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn, void *context) {
auto *ctor = cast<ConstructorDecl>(fn);
auto &ctx = ctor->getASTContext();
auto *superclassCtor = (ConstructorDecl *) context;
if (!superclassCtor->hasValidSignature())
ctx.getLazyResolver()->resolveDeclSignature(superclassCtor);
// Reference to super.init.
auto *selfDecl = ctor->getImplicitSelfDecl();
auto *superRef = buildSelfReference(selfDecl, SelfAccessorKind::Super,
/*isLValue=*/false, ctx);
SubstitutionMap subs;
if (auto *genericEnv = fn->getGenericEnvironment())
subs = genericEnv->getForwardingSubstitutionMap();
subs = SubstitutionMap::getOverrideSubstitutions(superclassCtor, fn, subs);
ConcreteDeclRef ctorRef(superclassCtor, subs);
auto type = superclassCtor->getInitializerInterfaceType()
.subst(subs, SubstFlags::UseErrorType);
auto *ctorRefExpr =
new (ctx) OtherConstructorDeclRefExpr(ctorRef, DeclNameLoc(),
IsImplicit, type);
if (auto *funcTy = type->getAs<FunctionType>())
type = funcTy->getResult();
auto *superclassCtorRefExpr =
new (ctx) DotSyntaxCallExpr(ctorRefExpr, SourceLoc(), superRef, type);
superclassCtorRefExpr->setIsSuper(true);
superclassCtorRefExpr->setThrows(false);
auto *bodyParams = ctor->getParameters();
auto ctorArgs = buildArgumentForwardingExpr(bodyParams->getArray(), ctx);
auto *superclassCallExpr =
CallExpr::create(ctx, superclassCtorRefExpr, ctorArgs,
superclassCtor->getFullName().getArgumentNames(), { },
/*hasTrailingClosure=*/false, /*implicit=*/true);
if (auto *funcTy = type->getAs<FunctionType>())
type = funcTy->getResult();
superclassCallExpr->setType(type);
superclassCallExpr->setThrows(superclassCtor->hasThrows());
Expr *expr = superclassCallExpr;
if (superclassCtor->hasThrows()) {
expr = new (ctx) TryExpr(SourceLoc(), expr, type, /*implicit=*/true);
}
auto *rebindSelfExpr =
new (ctx) RebindSelfInConstructorExpr(expr, selfDecl);
SmallVector<ASTNode, 2> stmts;
stmts.push_back(rebindSelfExpr);
stmts.push_back(new (ctx) ReturnStmt(SourceLoc(), /*Result=*/nullptr));
return { BraceStmt::create(ctx, SourceLoc(), stmts, SourceLoc(),
/*implicit=*/true),
/*isTypeChecked=*/true };
}
ConstructorDecl *
swift::createDesignatedInitOverride(TypeChecker &tc,
ClassDecl *classDecl,
ConstructorDecl *superclassCtor,
DesignatedInitKind kind) {
auto &ctx = tc.Context;
// Lookup will sometimes give us initializers that are from the ancestors of
// our immediate superclass. So, from the superclass constructor, we look
// one level up to the enclosing type context which will either be a class
// or an extension. We can use the type declared in that context to check
// if it's our immediate superclass and give up if we didn't.
//
// FIXME: Remove this when lookup of initializers becomes restricted to our
// immediate superclass.
auto *superclassCtorDecl =
superclassCtor->getDeclContext()->getSelfNominalTypeDecl();
Type superclassTy = classDecl->getSuperclass();
NominalTypeDecl *superclassDecl = superclassTy->getAnyNominal();
if (superclassCtorDecl != superclassDecl) {
return nullptr;
}
GenericEnvironment *genericEnv;
GenericParamList *genericParams;
SubstitutionMap subMap;
std::tie(genericEnv, genericParams, subMap) =
configureGenericDesignatedInitOverride(ctx,
classDecl,
superclassTy,
superclassCtor);
// Determine the initializer parameters.
// Create the initializer parameter patterns.
OptionSet<ParameterList::CloneFlags> options = ParameterList::Implicit;
options |= ParameterList::Inherited;
auto *bodyParams = superclassCtor->getParameters()->clone(ctx, options);
// If the superclass is generic, we need to map the superclass constructor's
// parameter types into the generic context of our class.
//
// We might have to apply substitutions, if for example we have a declaration
// like 'class A : B<Int>'.
for (auto *decl : *bodyParams) {
auto paramTy = decl->getInterfaceType();
auto substTy = paramTy.subst(subMap, SubstFlags::UseErrorType);
decl->setInterfaceType(substTy);
decl->getTypeLoc() = TypeLoc::withoutLoc(substTy);
}
// Create the initializer declaration, inheriting the name,
// failability, and throws from the superclass initializer.
auto ctor =
new (ctx) ConstructorDecl(superclassCtor->getFullName(),
classDecl->getBraces().Start,
superclassCtor->getFailability(),
/*FailabilityLoc=*/SourceLoc(),
/*Throws=*/superclassCtor->hasThrows(),
/*ThrowsLoc=*/SourceLoc(),
bodyParams, genericParams, classDecl);
ctor->setImplicit();
// Set the interface type of the initializer.
ctor->setGenericEnvironment(genericEnv);
ctor->computeType();
if (ctor->getFailability() == OTK_ImplicitlyUnwrappedOptional) {
ctor->getAttrs().add(
new (ctx) ImplicitlyUnwrappedOptionalAttr(/*implicit=*/true));
}
ctor->setValidationToChecked();
configureInheritedDesignatedInitAttributes(tc, classDecl, ctor,
superclassCtor);
if (kind == DesignatedInitKind::Stub) {
// Make this a stub implementation.
ctor->setBodySynthesizer(synthesizeStubBody);
// Note that this is a stub implementation.
ctor->setStubImplementation(true);
// Stub constructors don't appear in the vtable.
ctor->setNeedsNewVTableEntry(false);
return ctor;
}
// Form the body of a chaining designated initializer.
assert(kind == DesignatedInitKind::Chaining);
ctor->setBodySynthesizer(synthesizeDesignatedInitOverride, superclassCtor);
return ctor;
}