blob: 1770ba0307777d7f2eb76c1ca6efc38ce28aeb77 [file] [log] [blame]
//===--- 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/ProtocolConformance.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;
/// Should a particular accessor for the given storage be synthesized
/// on-demand, or is it always defined eagerly in the file that declared
/// the storage?
static bool isOnDemandAccessor(AbstractStorageDecl *storage,
AccessorKind kind) {
assert(kind == AccessorKind::Get ||
kind == AccessorKind::Set ||
kind == AccessorKind::Read ||
kind == AccessorKind::Modify);
// If the accessor isn't in the inherent opaque-accessor set of the
// declaration, it's on-demand.
if (!storage->requiresOpaqueAccessor(kind))
return true;
// Currently this only applies to imported declarations because we
// eagerly create accessors for all other member storage.
//
// Note that we can't just use hasClangNode() because the importer
// sometimes synthesizes things that lack clang nodes.
auto *mod = storage->getDeclContext()->getModuleScopeContext();
return (cast<FileUnit>(mod)->getKind() == FileUnitKind::ClangModule ||
cast<FileUnit>(mod)->getKind() == FileUnitKind::DWARFModule);
}
/// Insert the specified decl into the DeclContext's member list. If the hint
/// decl is specified, the new decl is inserted next to the hint.
static void addMemberToContextIfNeeded(Decl *D, DeclContext *DC,
Decl *Hint = nullptr) {
if (auto *ntd = dyn_cast<NominalTypeDecl>(DC)) {
ntd->addMember(D, Hint);
} else if (auto *ed = dyn_cast<ExtensionDecl>(DC)) {
ed->addMember(D, Hint);
} else {
assert((isa<AbstractFunctionDecl>(DC) || isa<FileUnit>(DC)) &&
"Unknown declcontext");
}
}
static ParamDecl *getParamDeclAtIndex(FuncDecl *fn, unsigned index) {
return fn->getParameters()->get(index);
}
static VarDecl *getFirstParamDecl(FuncDecl *fn) {
return getParamDeclAtIndex(fn, 0);
};
static ParamDecl *buildArgument(SourceLoc loc, DeclContext *DC,
StringRef name,
Type interfaceType,
VarDecl::Specifier specifier,
ASTContext &context) {
auto *param = new (context) ParamDecl(specifier, SourceLoc(), SourceLoc(),
Identifier(), loc,
context.getIdentifier(name),
DC);
param->setImplicit();
param->setInterfaceType(interfaceType);
return param;
}
/// Build a parameter list which can forward the formal index parameters of a
/// declaration.
///
/// \param prefix optional arguments to be prefixed onto the index
/// forwarding pattern.
static ParameterList *
buildIndexForwardingParamList(AbstractStorageDecl *storage,
ArrayRef<ParamDecl*> prefix,
ASTContext &context) {
auto subscript = dyn_cast<SubscriptDecl>(storage);
// Fast path: if this isn't a subscript, just use whatever we have.
if (!subscript)
return ParameterList::create(context, prefix);
// Clone the parameter list over for a new decl, so we get new ParamDecls.
auto indices = subscript->getIndices()->clone(context,
ParameterList::Implicit|
ParameterList::WithoutTypes);
// Give all of the parameters meaningless names so that we can forward
// them properly. If it's declared anonymously, SILGen will think
// it's unused.
// TODO: use some special DeclBaseName for this?
for (auto param : indices->getArray()) {
if (!param->hasName())
param->setName(context.getIdentifier("anonymous"));
assert(param->hasName());
}
if (prefix.empty())
return indices;
// Otherwise, we need to build up a new parameter list.
SmallVector<ParamDecl*, 4> elements;
// Start with the fields we were given, if there are any.
elements.append(prefix.begin(), prefix.end());
elements.append(indices->begin(), indices->end());
return ParameterList::create(context, elements);
}
/// Create the generic parameters needed for the given accessor, if any.
static GenericParamList *createAccessorGenericParams(
AbstractStorageDecl *storage) {
// Accessors of generic subscripts get a copy of the subscript's
// generic parameter list, because they're not nested inside the
// subscript.
if (auto *subscript = dyn_cast<SubscriptDecl>(storage)) {
if (auto genericParams = subscript->getGenericParams())
return genericParams->clone(subscript->getDeclContext());
}
return nullptr;
}
static AccessorDecl *createGetterPrototype(AbstractStorageDecl *storage,
ASTContext &ctx) {
assert(!storage->getGetter());
SourceLoc loc = storage->getLoc();
GenericEnvironment *genericEnvironmentOfLazyAccessor = nullptr;
ParamDecl *selfDecl = nullptr;
if (storage->getDeclContext()->isTypeContext()) {
if (storage->getAttrs().hasAttribute<LazyAttr>()) {
// For lazy properties, steal the 'self' from the initializer context.
auto *varDecl = cast<VarDecl>(storage);
auto *bindingDecl = varDecl->getParentPatternBinding();
auto *bindingInit = cast<PatternBindingInitializer>(
bindingDecl->getPatternEntryForVarDecl(varDecl).getInitContext());
selfDecl = bindingInit->getImplicitSelfDecl();
genericEnvironmentOfLazyAccessor =
bindingInit->getGenericEnvironmentOfContext();
}
}
GenericParamList *genericParams = createAccessorGenericParams(storage);
// Add an index-forwarding clause.
auto *getterParams = buildIndexForwardingParamList(storage, {}, ctx);
SourceLoc staticLoc;
if (auto var = dyn_cast<VarDecl>(storage)) {
if (var->isStatic())
staticLoc = var->getLoc();
}
auto storageInterfaceType = storage->getValueInterfaceType();
auto getter = AccessorDecl::create(
ctx, loc, /*AccessorKeywordLoc*/ loc,
AccessorKind::Get, storage,
staticLoc, StaticSpellingKind::None,
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
genericParams,
getterParams,
TypeLoc::withoutLoc(storageInterfaceType),
storage->getDeclContext());
getter->setImplicit();
// If we're stealing the 'self' from a lazy initializer, set it now.
// Note that we don't re-parent the 'self' declaration to be part of
// the getter until we synthesize the body of the getter later.
if (selfDecl)
*getter->getImplicitSelfDeclStorage() = selfDecl;
// We need to install the generic environment here because:
// 1) validating the getter will change the implicit self decl's DC to it,
// 2) it's likely that the initializer will be type-checked before the
// accessor (and therefore before the normal installation happens), and
// 3) type-checking a reference to the self decl will map its type into
// its context, which requires an environment to be installed on that
// context.
// We can safely use the enclosing environment because properties are never
// differently generic.
if (genericEnvironmentOfLazyAccessor)
getter->setGenericEnvironment(genericEnvironmentOfLazyAccessor);
if (storage->isGetterMutating())
getter->setSelfAccessKind(SelfAccessKind::Mutating);
if (storage->isStatic())
getter->setStatic();
if (!storage->requiresOpaqueAccessor(AccessorKind::Get))
getter->setForcedStaticDispatch(true);
// Always add the getter to the context immediately after the storage.
addMemberToContextIfNeeded(getter, storage->getDeclContext(), storage);
return getter;
}
static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage,
ASTContext &ctx,
AccessorDecl *getter = nullptr) {
assert(!storage->getSetter());
assert(storage->supportsMutation());
SourceLoc loc = storage->getLoc();
bool isStatic = storage->isStatic();
bool isMutating = storage->isSetterMutating();
GenericParamList *genericParams = createAccessorGenericParams(storage);
// Add a "(value : T, indices...)" argument list.
auto storageInterfaceType = storage->getValueInterfaceType();
auto valueDecl = buildArgument(storage->getLoc(), storage->getDeclContext(),
"value", storageInterfaceType,
VarDecl::Specifier::Default, ctx);
auto *params = buildIndexForwardingParamList(storage, valueDecl, ctx);
Type setterRetTy = TupleType::getEmpty(ctx);
auto setter = AccessorDecl::create(
ctx, loc, /*AccessorKeywordLoc*/ SourceLoc(),
AccessorKind::Set, storage,
/*StaticLoc=*/SourceLoc(), StaticSpellingKind::None,
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
genericParams, params,
TypeLoc::withoutLoc(setterRetTy),
storage->getDeclContext());
setter->setImplicit();
if (isMutating)
setter->setSelfAccessKind(SelfAccessKind::Mutating);
if (isStatic)
setter->setStatic();
// All mutable storage requires a setter.
assert(storage->requiresOpaqueAccessor(AccessorKind::Set));
// Always add the setter to the context immediately after the getter.
if (!getter) getter = storage->getGetter();
if (!getter) getter = storage->getReadCoroutine();
assert(getter && "always synthesize setter prototype after get/read");
addMemberToContextIfNeeded(setter, storage->getDeclContext(), getter);
return setter;
}
/// Mark the accessor as transparent if we can.
///
/// If the storage is inside a fixed-layout nominal type, we can mark the
/// accessor as transparent, since in this case we just want it for abstraction
/// purposes (i.e., to make access to the variable uniform and to be able to
/// put the getter in a vtable).
///
/// If the storage is for a global stored property or a stored property of a
/// resilient type, we are synthesizing accessors to present a resilient
/// interface to the storage and they should not be transparent.
static void maybeMarkTransparent(AccessorDecl *accessor, ASTContext &ctx) {
auto *DC = accessor->getDeclContext();
auto *nominalDecl = DC->getSelfNominalTypeDecl();
// Global variable accessors are not @_transparent.
if (!nominalDecl)
return;
// Accessors for resilient properties are not @_transparent.
if (accessor->getStorage()->isResilient())
return;
// Setters for lazy properties are not @_transparent (because the storage
// is not ABI-exposed).
if (accessor->getStorage()->getAttrs().hasAttribute<LazyAttr>() &&
accessor->getAccessorKind() == AccessorKind::Set)
return;
// Accessors for protocol storage requirements are never @_transparent
// since they do not have bodies.
//
// FIXME: Revisit this if we ever get 'real' default implementations.
if (isa<ProtocolDecl>(nominalDecl))
return;
// Accessors for classes with @objc ancestry are not @_transparent,
// since they use a field offset variable which is not exported.
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
if (classDecl->checkAncestry(AncestryFlags::ObjC))
return;
// Accessors synthesized on-demand are never transaprent.
if (accessor->hasForcedStaticDispatch())
return;
accessor->getAttrs().add(new (ctx) TransparentAttr(IsImplicit));
}
static AccessorDecl *
createCoroutineAccessorPrototype(AbstractStorageDecl *storage,
AccessorKind kind,
ASTContext &ctx) {
assert(kind == AccessorKind::Read || kind == AccessorKind::Modify);
SourceLoc loc = storage->getLoc();
bool isStatic = storage->isStatic();
bool isMutating = storage->isGetterMutating();
if (kind == AccessorKind::Modify)
isMutating |= storage->isSetterMutating();
auto dc = storage->getDeclContext();
// The forwarding index parameters.
auto *params = buildIndexForwardingParamList(storage, {}, ctx);
// Coroutine accessors always return ().
Type retTy = TupleType::getEmpty(ctx);
GenericParamList *genericParams = createAccessorGenericParams(storage);
auto *accessor = AccessorDecl::create(
ctx, loc, /*AccessorKeywordLoc=*/SourceLoc(),
kind, storage,
/*StaticLoc=*/SourceLoc(), StaticSpellingKind::None,
/*Throws=*/false, /*ThrowsLoc=*/SourceLoc(),
genericParams, params, TypeLoc::withoutLoc(retTy), dc);
accessor->setImplicit();
if (isMutating)
accessor->setSelfAccessKind(SelfAccessKind::Mutating);
if (isStatic)
accessor->setStatic();
// The accessor is final if the storage is.
if (storage->isFinal())
makeFinal(ctx, accessor);
// If the storage does not provide this accessor as an opaque accessor,
// we can't add a dynamically-dispatched method entry for the accessor,
// so force it to be statically dispatched. ("final" would be inappropriate
// because the property can still be overridden.)
if (!storage->requiresOpaqueAccessor(kind))
accessor->setForcedStaticDispatch(true);
// Make sure the coroutine is available enough to access
// the storage (and its getters/setters if it has them).
SmallVector<const Decl *, 2> asAvailableAs;
asAvailableAs.push_back(storage);
if (FuncDecl *getter = storage->getGetter()) {
asAvailableAs.push_back(getter);
}
if (kind == AccessorKind::Modify) {
if (FuncDecl *setter = storage->getSetter()) {
asAvailableAs.push_back(setter);
}
}
maybeMarkTransparent(accessor, ctx);
AvailabilityInference::applyInferredAvailableAttrs(accessor,
asAvailableAs, ctx);
Decl *afterDecl;
if (kind == AccessorKind::Read) {
// Add the synthesized read coroutine after the getter, if one exists,
// or else immediately after the storage.
afterDecl = storage->getGetter();
if (!afterDecl) afterDecl = storage;
} else {
// Add the synthesized modify coroutine after the setter.
afterDecl = storage->getSetter();
}
addMemberToContextIfNeeded(accessor, dc, afterDecl);
return accessor;
}
static AccessorDecl *
createReadCoroutinePrototype(AbstractStorageDecl *storage,
ASTContext &ctx) {
return createCoroutineAccessorPrototype(storage, AccessorKind::Read, ctx);
}
static AccessorDecl *
createModifyCoroutinePrototype(AbstractStorageDecl *storage,
ASTContext &ctx) {
return createCoroutineAccessorPrototype(storage, AccessorKind::Modify, ctx);
}
/// Build an expression that evaluates the specified parameter list as a tuple
/// or paren expr, suitable for use in an apply expr.
static Expr *buildArgumentForwardingExpr(ArrayRef<ParamDecl*> params,
ASTContext &ctx) {
SmallVector<Identifier, 4> labels;
SmallVector<SourceLoc, 4> labelLocs;
SmallVector<Expr *, 4> args;
for (auto param : params) {
Expr *ref = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true);
if (param->isInOut())
ref = new (ctx) InOutExpr(SourceLoc(), ref, Type(), /*isImplicit=*/true);
else if (param->isVariadic())
ref = new (ctx) VarargExpansionExpr(ref, /*implicit*/ true);
else if (param->isAutoClosure()) {
// If parameter is marked as `@autoclosure` it means
// that it has to be called.
auto arg = TupleExpr::createEmpty(ctx, SourceLoc(), SourceLoc(),
/*implicit=*/true);
ref = CallExpr::create(ctx, ref, arg, {}, {},
/*hasTrailingClosure=*/false,
/*implicit=*/true);
}
args.push_back(ref);
labels.push_back(param->getArgumentName());
labelLocs.push_back(SourceLoc());
}
// A single unlabeled value is not a tuple.
if (args.size() == 1 && labels[0].empty() &&
!isa<VarargExpansionExpr>(args[0])) {
return new (ctx) ParenExpr(SourceLoc(), args[0], SourceLoc(),
/*hasTrailingClosure=*/false);
}
return TupleExpr::create(ctx, SourceLoc(), args, labels, labelLocs,
SourceLoc(), false, IsImplicit);
}
/// Build a reference to the subscript index variables for this subscript
/// accessor.
static Expr *buildSubscriptIndexReference(ASTContext &ctx,
AccessorDecl *accessor) {
// Pull out the body parameters, which we should have cloned
// previously to be forwardable. Drop the initial buffer/value
// parameter in accessors that have one.
auto params = accessor->getParameters()->getArray();
auto accessorKind = accessor->getAccessorKind();
// Ignore the value parameter of a setter.
if (accessorKind == AccessorKind::Set) {
params = params.slice(1);
}
// Okay, everything else should be forwarded, build the expression.
auto result = buildArgumentForwardingExpr(params, ctx);
assert(result && "FIXME: Cannot forward expression");
return result;
}
enum class SelfAccessorKind {
/// We're building a derived accessor on top of whatever this
/// class provides.
Peer,
/// We're building a setter or something around an underlying
/// implementation, which might be storage or inherited from a
/// superclass.
Super,
};
static Expr *buildSelfReference(VarDecl *selfDecl,
SelfAccessorKind selfAccessorKind,
ASTContext &ctx) {
switch (selfAccessorKind) {
case SelfAccessorKind::Peer:
return new (ctx) DeclRefExpr(selfDecl, DeclNameLoc(), IsImplicit);
case SelfAccessorKind::Super:
return new (ctx) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit);
}
llvm_unreachable("bad self access kind");
}
namespace {
enum class TargetImpl {
/// We're doing an ordinary storage reference.
Ordinary,
/// We're referencing the physical storage created for the storage.
Storage,
/// We're referencing this specific implementation of the storage, not
/// an override of it.
Implementation,
/// We're referencing the superclass's implementation of the storage.
Super
};
} // end anonymous namespace
/// Build an l-value for the storage of a declaration.
static Expr *buildStorageReference(AccessorDecl *accessor,
AbstractStorageDecl *storage,
TargetImpl target,
ASTContext &ctx) {
AccessSemantics semantics;
SelfAccessorKind selfAccessKind;
switch (target) {
case TargetImpl::Ordinary:
semantics = AccessSemantics::Ordinary;
selfAccessKind = SelfAccessorKind::Peer;
break;
case TargetImpl::Storage:
semantics = AccessSemantics::DirectToStorage;
selfAccessKind = SelfAccessorKind::Peer;
break;
case TargetImpl::Implementation:
semantics = AccessSemantics::DirectToImplementation;
selfAccessKind = SelfAccessorKind::Peer;
break;
case TargetImpl::Super:
// If this really is an override, use a super-access.
if (auto override = storage->getOverriddenDecl()) {
semantics = AccessSemantics::Ordinary;
selfAccessKind = SelfAccessorKind::Super;
storage = override;
// Otherwise do a self-reference, which is dynamically bogus but
// should be statically valid. This should only happen in invalid cases.
} else {
assert(storage->isInvalid());
semantics = AccessSemantics::Ordinary;
selfAccessKind = SelfAccessorKind::Peer;
}
break;
}
VarDecl *selfDecl = accessor->getImplicitSelfDecl();
if (!selfDecl) {
assert(target != TargetImpl::Super);
return new (ctx) DeclRefExpr(storage, DeclNameLoc(), IsImplicit, semantics);
}
Expr *selfDRE =
buildSelfReference(selfDecl, selfAccessKind, ctx);
if (auto subscript = dyn_cast<SubscriptDecl>(storage)) {
Expr *indices = buildSubscriptIndexReference(ctx, accessor);
return SubscriptExpr::create(ctx, selfDRE, indices, storage,
IsImplicit, semantics);
}
return new (ctx) MemberRefExpr(selfDRE, SourceLoc(), storage,
DeclNameLoc(), IsImplicit, semantics);
}
/// Load the value of VD. If VD is an @override of another value, we call the
/// superclass getter. Otherwise, we do a direct load of the value.
static Expr *
createPropertyLoadOrCallSuperclassGetter(AccessorDecl *accessor,
AbstractStorageDecl *storage,
TargetImpl target,
ASTContext &ctx) {
return buildStorageReference(accessor, storage, target, ctx);
}
/// Look up the NSCopying protocol from the Foundation module, if present.
/// Otherwise return null.
static ProtocolDecl *getNSCopyingProtocol(ASTContext &ctx,
DeclContext *DC) {
auto foundation = ctx.getLoadedModule(ctx.Id_Foundation);
if (!foundation)
return nullptr;
SmallVector<ValueDecl *, 2> results;
DC->lookupQualified(foundation,
ctx.getSwiftId(KnownFoundationEntity::NSCopying),
NL_QualifiedDefault | NL_KnownNonCascadingDependency,
results);
if (results.size() != 1)
return nullptr;
return dyn_cast<ProtocolDecl>(results.front());
}
static bool checkConformanceToNSCopying(ASTContext &ctx, VarDecl *var,
Type type) {
auto dc = var->getDeclContext();
auto proto = getNSCopyingProtocol(ctx, dc);
if (!proto || !TypeChecker::conformsToProtocol(type, proto, dc, None)) {
ctx.Diags.diagnose(var->getLoc(), diag::nscopying_doesnt_conform);
return true;
}
return false;
}
static std::pair<Type, bool> getUnderlyingTypeOfVariable(VarDecl *var) {
Type type = var->getType()->getReferenceStorageReferent();
if (Type objectType = type->getOptionalObjectType()) {
return {objectType, true};
} else {
return {type, false};
}
}
bool TypeChecker::checkConformanceToNSCopying(VarDecl *var) {
Type type = getUnderlyingTypeOfVariable(var).first;
return ::checkConformanceToNSCopying(Context, var, type);
}
/// Synthesize the code to store 'Val' to 'VD', given that VD has an @NSCopying
/// attribute on it. We know that VD is a stored property in a class, so we
/// just need to generate something like "self.property = val.copy(zone: nil)"
/// here. This does some type checking to validate that the call will succeed.
static Expr *synthesizeCopyWithZoneCall(Expr *Val, VarDecl *VD,
ASTContext &Ctx) {
// We support @NSCopying on class types (which conform to NSCopying),
// protocols which conform, and option types thereof.
auto underlyingTypeAndIsOptional = getUnderlyingTypeOfVariable(VD);
auto underlyingType = underlyingTypeAndIsOptional.first;
auto isOptional = underlyingTypeAndIsOptional.second;
// The element type must conform to NSCopying. If not, emit an error and just
// recovery by synthesizing without the copy call.
if (checkConformanceToNSCopying(Ctx, VD, underlyingType)) {
return Val;
}
// If we have an optional type, we have to "?" the incoming value to only
// evaluate the subexpression if the incoming value is non-null.
if (isOptional)
Val = new (Ctx) BindOptionalExpr(Val, SourceLoc(), 0);
// Generate:
// (force_value_expr type='<null>'
// (call_expr type='<null>'
// (unresolved_dot_expr type='<null>' field 'copy'
// "Val")
// (paren_expr type='<null>'
// (nil_literal_expr type='<null>'))))
auto UDE = new (Ctx) UnresolvedDotExpr(Val, SourceLoc(),
Ctx.getIdentifier("copy"),
DeclNameLoc(), /*implicit*/true);
Expr *Nil = new (Ctx) NilLiteralExpr(SourceLoc(), /*implicit*/true);
//- (id)copyWithZone:(NSZone *)zone;
Expr *Call = CallExpr::createImplicit(Ctx, UDE, { Nil }, { Ctx.Id_with });
TypeLoc ResultTy;
ResultTy.setType(VD->getType());
// If we're working with non-optional types, we're forcing the cast.
if (!isOptional) {
Call = new (Ctx) ForcedCheckedCastExpr(Call, SourceLoc(), SourceLoc(),
TypeLoc::withoutLoc(underlyingType));
Call->setImplicit();
return Call;
}
// We're working with optional types, so perform a conditional checked
// downcast.
Call = new (Ctx) ConditionalCheckedCastExpr(Call, SourceLoc(), SourceLoc(),
TypeLoc::withoutLoc(underlyingType));
Call->setImplicit();
// Use OptionalEvaluationExpr to evaluate the "?".
return new (Ctx) OptionalEvaluationExpr(Call);
}
/// In a synthesized accessor body, store 'value' to the appropriate element.
///
/// If the property is an override, we call the superclass setter.
/// Otherwise, we do a direct store of the value.
static
void createPropertyStoreOrCallSuperclassSetter(AccessorDecl *accessor,
Expr *value,
AbstractStorageDecl *storage,
TargetImpl target,
SmallVectorImpl<ASTNode> &body,
ASTContext &ctx) {
// If the storage is an @NSCopying property, then we store the
// result of a copyWithZone call on the value, not the value itself.
if (auto property = dyn_cast<VarDecl>(storage)) {
if (property->getAttrs().hasAttribute<NSCopyingAttr>())
value = synthesizeCopyWithZoneCall(value, property, ctx);
}
// Create:
// (assign (decl_ref_expr(VD)), decl_ref_expr(value))
// or:
// (assign (member_ref_expr(decl_ref_expr(self), VD)), decl_ref_expr(value))
Expr *dest = buildStorageReference(accessor, storage, target, ctx);
body.push_back(new (ctx) AssignExpr(dest, SourceLoc(), value,
IsImplicit));
}
LLVM_ATTRIBUTE_UNUSED
static bool isSynthesizedComputedProperty(AbstractStorageDecl *storage) {
return (storage->getAttrs().hasAttribute<LazyAttr>() ||
storage->getAttrs().hasAttribute<NSManagedAttr>());
}
/// Synthesize the body of a trivial getter. For a non-member vardecl or one
/// which is not an override of a base class property, it performs a direct
/// storage load. For an override of a base member property, it chains up to
/// super.
static void synthesizeTrivialGetterBody(AccessorDecl *getter,
TargetImpl target,
ASTContext &ctx) {
auto storage = getter->getStorage();
assert(!storage->getAttrs().hasAttribute<LazyAttr>() &&
!storage->getAttrs().hasAttribute<NSManagedAttr>());
SourceLoc loc = storage->getLoc();
Expr *result =
createPropertyLoadOrCallSuperclassGetter(getter, storage, target, ctx);
ASTNode returnStmt = new (ctx) ReturnStmt(SourceLoc(), result, IsImplicit);
getter->setBody(BraceStmt::create(ctx, loc, returnStmt, loc, true));
maybeMarkTransparent(getter, ctx);
}
/// Synthesize the body of a getter which just directly accesses the
/// underlying storage.
static void synthesizeTrivialGetterBody(AccessorDecl *getter,
ASTContext &ctx) {
assert(getter->getStorage()->hasStorage());
synthesizeTrivialGetterBody(getter, TargetImpl::Storage, ctx);
}
/// Synthesize the body of a getter which just delegates to its superclass
/// implementation.
static void synthesizeInheritedGetterBody(AccessorDecl *getter,
ASTContext &ctx) {
// This should call the superclass getter.
synthesizeTrivialGetterBody(getter, TargetImpl::Super, ctx);
}
/// Synthesize the body of a getter which just delegates to an addressor.
static void synthesizeAddressedGetterBody(AccessorDecl *getter,
ASTContext &ctx) {
assert(getter->getStorage()->getAddressor());
// This should call the addressor.
synthesizeTrivialGetterBody(getter, TargetImpl::Implementation, ctx);
}
/// Synthesize the body of a getter which just delegates to a read
/// coroutine accessor.
static void synthesizeReadCoroutineGetterBody(AccessorDecl *getter,
ASTContext &ctx) {
assert(getter->getStorage()->getReadCoroutine());
// This should call the read coroutine.
synthesizeTrivialGetterBody(getter, TargetImpl::Implementation, ctx);
}
/// Synthesize the body of a setter which just stores to the given storage
/// declaration (which doesn't have to be the storage for the setter).
static void
synthesizeTrivialSetterBodyWithStorage(AccessorDecl *setter,
TargetImpl target,
AbstractStorageDecl *storageToUse,
ASTContext &ctx) {
SourceLoc loc = setter->getStorage()->getLoc();
VarDecl *valueParamDecl = getFirstParamDecl(setter);
auto *valueDRE =
new (ctx) DeclRefExpr(valueParamDecl, DeclNameLoc(), IsImplicit);
SmallVector<ASTNode, 1> setterBody;
createPropertyStoreOrCallSuperclassSetter(setter, valueDRE, storageToUse,
target, setterBody, ctx);
setter->setBody(BraceStmt::create(ctx, loc, setterBody, loc, true));
maybeMarkTransparent(setter, ctx);
}
static void synthesizeTrivialSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
auto storage = setter->getStorage();
assert(!isSynthesizedComputedProperty(storage));
synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::Storage,
storage, ctx);
}
static void synthesizeCoroutineAccessorBody(AccessorDecl *accessor,
ASTContext &ctx) {
assert(accessor->isCoroutine());
auto storage = accessor->getStorage();
auto target = (accessor->hasForcedStaticDispatch()
? TargetImpl::Ordinary
: TargetImpl::Implementation);
SourceLoc loc = storage->getLoc();
SmallVector<ASTNode, 1> body;
// Build a reference to the storage.
Expr *ref = buildStorageReference(accessor, storage, target, ctx);
// Wrap it with an `&` marker if this is a modify.
if (accessor->getAccessorKind() == AccessorKind::Modify) {
ref = new (ctx) InOutExpr(SourceLoc(), ref, Type(), true);
}
// Yield it.
YieldStmt *yield = YieldStmt::create(ctx, loc, loc, ref, loc, true);
body.push_back(yield);
accessor->setBody(BraceStmt::create(ctx, loc, body, loc, true));
maybeMarkTransparent(accessor, ctx);
}
/// Synthesize the body of a read coroutine.
static void synthesizeReadCoroutineBody(AccessorDecl *read,
ASTContext &ctx) {
assert(read->getStorage()->getReadImpl() != ReadImplKind::Read);
synthesizeCoroutineAccessorBody(read, ctx);
}
/// Synthesize the body of a modify coroutine.
static void synthesizeModifyCoroutineBody(AccessorDecl *modify,
ASTContext &ctx) {
#ifndef NDEBUG
auto impl = modify->getStorage()->getReadWriteImpl();
assert(impl != ReadWriteImplKind::Modify &&
impl != ReadWriteImplKind::Immutable);
#endif
synthesizeCoroutineAccessorBody(modify, ctx);
}
static void addGetterToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
auto getter = createGetterPrototype(storage, ctx);
// Install the prototype.
storage->setSynthesizedGetter(getter);
}
static void addSetterToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
auto setter = createSetterPrototype(storage, ctx);
// Install the prototype.
storage->setSynthesizedSetter(setter);
}
static void addReadCoroutineToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
auto read = createReadCoroutinePrototype(storage, ctx);
// Install the prototype.
storage->setSynthesizedReadCoroutine(read);
}
static void addModifyCoroutineToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
auto modify = createModifyCoroutinePrototype(storage, ctx);
// Install the prototype.
storage->setSynthesizedModifyCoroutine(modify);
}
static void addOpaqueAccessorToStorage(AbstractStorageDecl *storage,
AccessorKind kind,
ASTContext &ctx) {
switch (kind) {
case AccessorKind::Get:
return addGetterToStorage(storage, ctx);
case AccessorKind::Set:
return addSetterToStorage(storage, ctx);
case AccessorKind::Read:
return addReadCoroutineToStorage(storage, ctx);
case AccessorKind::Modify:
return addModifyCoroutineToStorage(storage, ctx);
#define OPAQUE_ACCESSOR(ID, KEYWORD)
#define ACCESSOR(ID) \
case AccessorKind::ID:
#include "swift/AST/AccessorKinds.def"
llvm_unreachable("not an opaque accessor");
}
}
static void addExpectedOpaqueAccessorsToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
// Nameless vars from interface files should not have any accessors.
// TODO: Replace this check with a broader check that all storage decls
// from interface files have all their accessors up front.
if (storage->getBaseName().empty())
return;
storage->visitExpectedOpaqueAccessors([&](AccessorKind kind) {
// If the accessor is already present, there's nothing to do.
if (storage->getAccessor(kind))
return;
addOpaqueAccessorToStorage(storage, kind, ctx);
});
}
/// Add trivial accessors to a Stored or Addressed property.
static void addTrivialAccessorsToStorage(AbstractStorageDecl *storage,
ASTContext &ctx) {
assert(!isSynthesizedComputedProperty(storage));
addExpectedOpaqueAccessorsToStorage(storage, ctx);
}
static StorageImplInfo getProtocolStorageImpl(AbstractStorageDecl *storage) {
auto protocol = cast<ProtocolDecl>(storage->getDeclContext());
if (protocol->isObjC()) {
return StorageImplInfo::getComputed(storage->supportsMutation());
} else {
return StorageImplInfo::getOpaque(storage->supportsMutation(),
storage->getOpaqueReadOwnership());
}
}
/// Given a storage declaration in a protocol, set it up with the right
/// StorageImpl and add the right set of opaque accessors.
static void setProtocolStorageImpl(AbstractStorageDecl *storage,
ASTContext &ctx) {
addExpectedOpaqueAccessorsToStorage(storage, ctx);
storage->overwriteImplInfo(getProtocolStorageImpl(storage));
}
/// Synthesize the body of a setter which just delegates to a mutable
/// addressor.
static void synthesizeMutableAddressSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
// This should call the mutable addressor.
synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::Implementation,
setter->getStorage(), ctx);
}
/// Synthesize the body of a setter which just delegates to a modify
/// coroutine accessor.
static void synthesizeModifyCoroutineSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
// This should call the modify coroutine.
synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::Implementation,
setter->getStorage(), ctx);
}
static void convertNSManagedStoredVarToComputed(VarDecl *VD, ASTContext &ctx) {
// If it's not still stored, just bail out.
if (!VD->getImplInfo().isSimpleStored())
return;
// We might already have synthesized the getter and setter declarations
// from e.g. type-checking a conformance, or just from an invalid earlier
// declaration.
// Creating these this way will not trigger synthesis of implementations
// because of the NSManaged attribute.
// Create the getter.
if (!VD->getGetter()) {
addGetterToStorage(VD, ctx);
}
// Create the setter.
if (!VD->getSetter()) {
addSetterToStorage(VD, ctx);
}
// Okay, we have both a getter and setter; overwrite the impl info.
VD->overwriteImplInfo(StorageImplInfo::getMutableComputed());
addExpectedOpaqueAccessorsToStorage(VD, ctx);
}
void synthesizeAccessorBody(AbstractFunctionDecl *fn, void *);
/// The specified AbstractStorageDecl was just found to satisfy a
/// protocol property requirement. Ensure that it has the full
/// complement of accessors.
void TypeChecker::synthesizeWitnessAccessorsForStorage(
AbstractStorageDecl *requirement,
AbstractStorageDecl *storage) {
bool addedAccessor = false;
requirement->visitExpectedOpaqueAccessors([&](AccessorKind kind) {
// If the accessor already exists, we have nothing to do.
if (storage->getAccessor(kind))
return;
// Otherwise, synthesize it.
addOpaqueAccessorToStorage(storage, kind, Context);
// Flag that we've added an accessor.
addedAccessor = true;
// Trigger synthesize of the accessor body if it's created on-demand.
if (isOnDemandAccessor(storage, kind)) {
auto *accessor = storage->getAccessor(kind);
assert(!accessor->hasBody());
accessor->setBodySynthesizer(&synthesizeAccessorBody);
// Make sure SILGen emits the accessor; on-demand accessors have shared
// linkage, and if its defined in a different translation unit from the
// conformance we cannot simply generate an external declaration.
Context.addExternalDecl(accessor);
DeclsToFinalize.insert(accessor);
}
});
// Cue (delayed) validation of any accessors we just added, just
// in case this is coming after the normal delayed validation finished.
if (addedAccessor) {
DeclsToFinalize.insert(storage);
}
}
/// Given a VarDecl with a willSet: and/or didSet: specifier, synthesize the
/// setter which calls them.
static void synthesizeObservedSetterBody(AccessorDecl *Set,
TargetImpl target,
ASTContext &Ctx) {
auto VD = cast<VarDecl>(Set->getStorage());
SourceLoc Loc = VD->getLoc();
// We have to be paranoid about the accessors already having bodies
// because there might be an (invalid) existing definition.
// Okay, the getter is done, create the setter now. Start by finding the
// decls for 'self' and 'value'.
auto *SelfDecl = Set->getImplicitSelfDecl();
VarDecl *ValueDecl = Set->getParameters()->get(0);
// The setter loads the oldValue, invokes willSet with the incoming value,
// does a direct store, then invokes didSet with the oldValue.
SmallVector<ASTNode, 6> SetterBody;
// If there is a didSet, it will take the old value. Load it into a temporary
// 'let' so we have it for later.
// TODO: check the body of didSet to only do this load (which may call the
// superclass getter) if didSet takes an argument.
VarDecl *OldValue = nullptr;
if (VD->getDidSetFunc()) {
Expr *OldValueExpr
= createPropertyLoadOrCallSuperclassGetter(Set, VD, target, Ctx);
OldValue = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp"), Set);
OldValue->setImplicit();
auto *tmpPattern = new (Ctx) NamedPattern(OldValue, /*implicit*/ true);
auto *tmpPBD = PatternBindingDecl::createImplicit(
Ctx, StaticSpellingKind::None, tmpPattern, OldValueExpr, Set);
SetterBody.push_back(tmpPBD);
SetterBody.push_back(OldValue);
}
// Create:
// (call_expr (dot_syntax_call_expr (decl_ref_expr(willSet)),
// (decl_ref_expr(self))),
// (declrefexpr(value)))
// or:
// (call_expr (decl_ref_expr(willSet)), (declrefexpr(value)))
if (auto willSet = VD->getWillSetFunc()) {
Expr *Callee = new (Ctx) DeclRefExpr(willSet, DeclNameLoc(), /*imp*/true);
auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, DeclNameLoc(),
/*imp*/true);
if (SelfDecl) {
auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, DeclNameLoc(),
/*imp*/true);
Callee = new (Ctx) DotSyntaxCallExpr(Callee, SourceLoc(), SelfDRE);
}
SetterBody.push_back(CallExpr::createImplicit(Ctx, Callee, { ValueDRE },
{ Identifier() }));
}
// Create an assignment into the storage or call to superclass setter.
auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, DeclNameLoc(), true);
createPropertyStoreOrCallSuperclassSetter(Set, ValueDRE, VD, target,
SetterBody, Ctx);
// Create:
// (call_expr (dot_syntax_call_expr (decl_ref_expr(didSet)),
// (decl_ref_expr(self))),
// (decl_ref_expr(tmp)))
// or:
// (call_expr (decl_ref_expr(didSet)), (decl_ref_expr(tmp)))
if (auto didSet = VD->getDidSetFunc()) {
auto *OldValueExpr = new (Ctx) DeclRefExpr(OldValue, DeclNameLoc(),
/*impl*/true);
Expr *Callee = new (Ctx) DeclRefExpr(didSet, DeclNameLoc(), /*imp*/true);
if (SelfDecl) {
auto *SelfDRE = new (Ctx) DeclRefExpr(SelfDecl, DeclNameLoc(),
/*imp*/true);
Callee = new (Ctx) DotSyntaxCallExpr(Callee, SourceLoc(), SelfDRE);
}
SetterBody.push_back(CallExpr::createImplicit(Ctx, Callee, { OldValueExpr },
{ Identifier() }));
}
Set->setBody(BraceStmt::create(Ctx, Loc, SetterBody, Loc, true));
}
static void synthesizeStoredWithObserversSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
synthesizeObservedSetterBody(setter, TargetImpl::Storage, ctx);
}
static void synthesizeInheritedWithObserversSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
synthesizeObservedSetterBody(setter, TargetImpl::Super, ctx);
}
namespace {
/// This ASTWalker explores an expression tree looking for expressions (which
/// are DeclContext's) and changes their parent DeclContext to NewDC.
class RecontextualizeClosures : public ASTWalker {
DeclContext *NewDC;
public:
RecontextualizeClosures(DeclContext *NewDC) : NewDC(NewDC) {}
std::pair<bool, Expr *> walkToExprPre(Expr *E) override {
// If we find a closure, update its declcontext and do *not* walk into it.
if (auto CE = dyn_cast<AbstractClosureExpr>(E)) {
CE->setParent(NewDC);
return { false, E };
}
if (auto CLE = dyn_cast<CaptureListExpr>(E)) {
// Make sure to recontextualize any decls in the capture list as well.
for (auto &CLE : CLE->getCaptureList()) {
CLE.Var->setDeclContext(NewDC);
CLE.Init->setDeclContext(NewDC);
}
}
// Unlike a closure, a TapExpr is not a DeclContext, so we need to
// recontextualize its variable and then anything else in its body.
// FIXME: Might be better to change walkToDeclPre() and walkToStmtPre()
// below, but I don't know what other effects that might have.
if (auto TE = dyn_cast<TapExpr>(E)) {
TE->getVar()->setDeclContext(NewDC);
for (auto node : TE->getBody()->getElements())
node.walk(RecontextualizeClosures(NewDC));
}
return { true, E };
}
/// We don't want to recurse into declarations or statements.
bool walkToDeclPre(Decl *) override { return false; }
std::pair<bool, Stmt*> walkToStmtPre(Stmt *S) override { return {false,S}; }
};
} // end anonymous namespace
/// Synthesize the getter for a lazy property with the specified storage
/// vardecl.
static void synthesizeLazyGetterBody(AbstractFunctionDecl *fn, void *context) {
auto &Ctx = fn->getASTContext();
// FIXME: Remove TypeChecker dependencies below.
auto &TC = *(TypeChecker *) Ctx.getLazyResolver();
// The stored property backing the lazy var.
AccessorDecl *Get = cast<AccessorDecl>(fn);
VarDecl *Storage = (VarDecl *) context;
// The lazy var itself.
auto VD = cast<VarDecl>(Get->getStorage());
if (Get->isInvalid() || Ctx.hadError())
return;
// The getter checks the optional, storing the initial value in if nil. The
// specific pattern we generate is:
// get {
// let tmp1 = storage
// if tmp1 {
// return tmp1!
// }
// let tmp2 : Ty = <<initializer expression>>
// storage = tmp2
// return tmp2
// }
SmallVector<ASTNode, 6> Body;
// Load the existing storage and store it into the 'tmp1' temporary.
auto *Tmp1VD = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp1"), Get);
Tmp1VD->setImplicit();
auto *Tmp1PBDPattern = new (Ctx) NamedPattern(Tmp1VD, /*implicit*/true);
auto *Tmp1Init =
createPropertyLoadOrCallSuperclassGetter(Get, Storage,
TargetImpl::Storage, Ctx);
auto *Tmp1PBD = PatternBindingDecl::createImplicit(
Ctx, StaticSpellingKind::None, Tmp1PBDPattern, Tmp1Init, Get);
Body.push_back(Tmp1PBD);
Body.push_back(Tmp1VD);
// Build the early return inside the if.
auto *Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, DeclNameLoc(), /*Implicit*/true,
AccessSemantics::DirectToStorage);
auto *EarlyReturnVal = new (Ctx) ForceValueExpr(Tmp1DRE, SourceLoc());
auto *Return = new (Ctx) ReturnStmt(SourceLoc(), EarlyReturnVal,
/*implicit*/true);
// Build the "if" around the early return.
Tmp1DRE = new (Ctx) DeclRefExpr(Tmp1VD, DeclNameLoc(), /*Implicit*/true,
AccessSemantics::DirectToStorage);
// Call through "hasValue" on the decl ref.
Tmp1DRE->setType(OptionalType::get(VD->getType()));
constraints::ConstraintSystem cs(TC,
VD->getDeclContext(),
constraints::ConstraintSystemOptions());
constraints::Solution solution(cs, constraints::Score());
auto HasValueExpr = solution.convertOptionalToBool(Tmp1DRE, nullptr);
Body.push_back(new (Ctx) IfStmt(SourceLoc(), HasValueExpr, Return,
/*elseloc*/SourceLoc(), /*else*/nullptr,
/*implicit*/ true, Ctx));
auto *Tmp2VD = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let,
/*IsCaptureList*/false, SourceLoc(),
Ctx.getIdentifier("tmp2"),
Get);
Tmp2VD->setType(VD->getType());
Tmp2VD->setInterfaceType(VD->getInterfaceType());
Tmp2VD->setImplicit();
// Take the initializer from the PatternBindingDecl for VD.
// TODO: This doesn't work with complicated patterns like:
// lazy var (a,b) = foo()
auto *InitValue = VD->getParentInitializer();
auto PBD = VD->getParentPatternBinding();
unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD);
assert(PBD->isInitializerLazy(entryIndex));
bool wasInitializerChecked = PBD->isInitializerChecked(entryIndex);
PBD->setInitializerChecked(entryIndex);
// Recontextualize any closure declcontexts nested in the initializer to
// realize that they are in the getter function.
Get->getImplicitSelfDecl()->setDeclContext(Get);
InitValue->walk(RecontextualizeClosures(Get));
// Wrap the initializer in a LazyInitializerExpr to avoid problems with
// re-typechecking it if it was already type-checked.
// FIXME: we should really have stronger invariants than this. Leaving it
// unwrapped may expose both expressions to naive walkers
if (wasInitializerChecked) {
auto initType = InitValue->getType();
InitValue = new (Ctx) LazyInitializerExpr(InitValue);
InitValue->setType(initType);
}
Pattern *Tmp2PBDPattern = new (Ctx) NamedPattern(Tmp2VD, /*implicit*/true);
Tmp2PBDPattern =
TypedPattern::createImplicit(Ctx, Tmp2PBDPattern, VD->getType());
auto *Tmp2PBD = PatternBindingDecl::createImplicit(
Ctx, StaticSpellingKind::None, Tmp2PBDPattern, InitValue, Get,
/*VarLoc*/ InitValue->getStartLoc());
Body.push_back(Tmp2PBD);
Body.push_back(Tmp2VD);
// Assign tmp2 into storage.
auto Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, DeclNameLoc(), /*Implicit*/true,
AccessSemantics::DirectToStorage);
createPropertyStoreOrCallSuperclassSetter(Get, Tmp2DRE, Storage,
TargetImpl::Storage, Body, Ctx);
// Return tmp2.
Tmp2DRE = new (Ctx) DeclRefExpr(Tmp2VD, DeclNameLoc(), /*Implicit*/true,
AccessSemantics::DirectToStorage);
Body.push_back(new (Ctx) ReturnStmt(SourceLoc(), Tmp2DRE, /*implicit*/true));
Get->setBody(BraceStmt::create(Ctx, VD->getLoc(), Body, VD->getLoc(),
/*implicit*/true));
}
static void synthesizeLazySetterBody(AbstractFunctionDecl *fn, void *context) {
auto *setter = cast<AccessorDecl>(fn);
auto *underlyingStorage = (VarDecl *) context;
auto &ctx = setter->getASTContext();
if (setter->isInvalid() || ctx.hadError())
return;
synthesizeTrivialSetterBodyWithStorage(setter, TargetImpl::Storage,
underlyingStorage, ctx);
}
void swift::completeLazyVarImplementation(VarDecl *VD) {
auto &Context = VD->getASTContext();
assert(VD->getAttrs().hasAttribute<LazyAttr>());
assert(VD->getReadImpl() == ReadImplKind::Get);
assert(VD->getWriteImpl() == WriteImplKind::Set);
assert(!VD->isStatic() && "Static vars are already lazy on their own");
// Create the storage property as an optional of VD's type.
SmallString<64> NameBuf;
NameBuf += "$__lazy_storage_$_";
NameBuf += VD->getName().str();
auto StorageName = Context.getIdentifier(NameBuf);
auto StorageTy = OptionalType::get(VD->getType());
auto StorageInterfaceTy = OptionalType::get(VD->getInterfaceType());
auto *Storage = new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var,
/*IsCaptureList*/false, VD->getLoc(),
StorageName,
VD->getDeclContext());
Storage->setInterfaceType(StorageInterfaceTy);
Storage->setUserAccessible(false);
addMemberToContextIfNeeded(Storage, VD->getDeclContext(), VD);
// Create the pattern binding decl for the storage decl. This will get
// default initialized to nil.
Pattern *PBDPattern = new (Context) NamedPattern(Storage, /*implicit*/true);
PBDPattern = TypedPattern::createImplicit(Context, PBDPattern, StorageTy);
auto *PBD = PatternBindingDecl::createImplicit(
Context, StaticSpellingKind::None, PBDPattern, /*init*/ nullptr,
VD->getDeclContext(), /*VarLoc*/ VD->getLoc());
addMemberToContextIfNeeded(PBD, VD->getDeclContext(), VD);
// Now that we've got the storage squared away, enqueue the getter and
// setter to be synthesized.
VD->getGetter()->setBodySynthesizer(&synthesizeLazyGetterBody, Storage);
VD->getSetter()->setBodySynthesizer(&synthesizeLazySetterBody, Storage);
// Mark the vardecl to be final, implicit, and private. In a class, this
// prevents it from being dynamically dispatched. Note that we do this after
// the accessors are set up, because we don't want the setter for the lazy
// property to inherit these properties from the storage.
if (VD->getDeclContext()->getSelfClassDecl())
makeFinal(Context, Storage);
Storage->setImplicit();
Storage->overwriteAccess(AccessLevel::Private);
Storage->overwriteSetterAccess(AccessLevel::Private);
}
static bool wouldBeCircularSynthesis(AbstractStorageDecl *storage,
AccessorKind kind) {
switch (kind) {
case AccessorKind::Get:
return storage->getReadImpl() == ReadImplKind::Get;
case AccessorKind::Read:
return storage->getReadImpl() == ReadImplKind::Read;
case AccessorKind::Set:
return storage->getWriteImpl() == WriteImplKind::Set;
case AccessorKind::Modify:
return storage->getReadWriteImpl() == ReadWriteImplKind::Modify;
#define OPAQUE_ACCESSOR(ID, KEYWORD)
#define ACCESSOR(ID) \
case AccessorKind::ID:
#include "swift/AST/AccessorKinds.def"
llvm_unreachable("unexpected opaque accessor");
}
llvm_unreachable("bad kind");
}
void swift::triggerAccessorSynthesis(TypeChecker &TC,
AbstractStorageDecl *storage) {
auto VD = dyn_cast<VarDecl>(storage);
maybeAddAccessorsToStorage(storage);
// Synthesize accessors for lazy, all checking already been performed.
bool lazy = false;
if (VD && VD->getAttrs().hasAttribute<LazyAttr>() && !VD->isStatic() &&
!VD->getGetter()->hasBody()) {
completeLazyVarImplementation(VD);
lazy = true;
}
// Trigger accessor synthesis.
storage->visitExpectedOpaqueAccessors([&](AccessorKind kind) {
// Ignore 'get' and 'set' for variables that we triggered above.
// TODO: just record the lazy-storage link in the AST, don't trigger
// in completeLazyVarImplementation, and remove this special case.
if (lazy && (kind == AccessorKind::Get || kind == AccessorKind::Set))
return;
// Don't synthesize an accessor if the accessor is supposed to be
// the basis of the storage implementation.
if (wouldBeCircularSynthesis(storage, kind))
return;
// Don't try to synthesize an accessor that doesn't exist.
// TODO: should this be an assertion?
auto accessor = storage->getAccessor(kind);
if (!accessor)
return;
accessor->setBodySynthesizer(&synthesizeAccessorBody);
TC.Context.addSynthesizedDecl(accessor);
TC.DeclsToFinalize.insert(accessor);
});
}
static void maybeAddAccessorsToLazyVariable(VarDecl *var, ASTContext &ctx) {
// If there are already accessors, something is invalid; bail out.
if (!var->getImplInfo().isSimpleStored())
return;
if (!var->getGetter()) {
addGetterToStorage(var, ctx);
}
if (!var->getSetter()) {
addSetterToStorage(var, ctx);
}
var->overwriteImplInfo(StorageImplInfo::getMutableComputed());
addExpectedOpaqueAccessorsToStorage(var, ctx);
}
/// Try to add the appropriate accessors required a storage declaration.
/// This needs to be idempotent.
///
/// Note that the parser synthesizes accessors in some cases:
/// - it synthesizes a getter and setter for an observing property
/// - it synthesizes a setter for get+mutableAddress
void swift::maybeAddAccessorsToStorage(AbstractStorageDecl *storage) {
auto &ctx = storage->getASTContext();
// Lazy properties require special handling.
if (storage->getAttrs().hasAttribute<LazyAttr>()) {
maybeAddAccessorsToLazyVariable(cast<VarDecl>(storage), ctx);
return;
}
auto *dc = storage->getDeclContext();
// Local variables don't otherwise get accessors.
if (dc->isLocalContext())
return;
// Implicit properties don't get accessors.
if (storage->isImplicit())
return;
if (!dc->isTypeContext()) {
// dynamic globals need accessors.
if (dc->isModuleScopeContext() && storage->isNativeDynamic()) {
addTrivialAccessorsToStorage(storage, ctx);
return;
}
// Fixed-layout global variables don't get accessors.
if (!storage->isResilient())
return;
// In a protocol context, variables written as just "var x : Int" or
// "let x : Int" are errors and recovered by building a computed property
// with just a getter. Diagnose this and create the getter decl now.
} else if (isa<ProtocolDecl>(dc)) {
if (storage->hasStorage()) {
auto var = cast<VarDecl>(storage);
if (var->isLet()) {
ctx.Diags.diagnose(var->getLoc(),
diag::protocol_property_must_be_computed_var)
.fixItReplace(var->getParentPatternBinding()->getLoc(), "var")
.fixItInsertAfter(var->getTypeLoc().getLoc(), " { get }");
} else {
auto diag = ctx.Diags.diagnose(var->getLoc(),
diag::protocol_property_must_be_computed);
auto braces = var->getBracesRange();
if (braces.isValid())
diag.fixItReplace(braces, "{ get <#set#> }");
else
diag.fixItInsertAfter(var->getTypeLoc().getLoc(), " { get <#set#> }");
}
}
setProtocolStorageImpl(storage, ctx);
return;
// NSManaged properties on classes require special handling.
} else if (dc->getSelfClassDecl()) {
auto var = dyn_cast<VarDecl>(storage);
if (var && var->getAttrs().hasAttribute<NSManagedAttr>()) {
convertNSManagedStoredVarToComputed(var, ctx);
return;
}
// Stored properties imported from Clang don't get accessors.
} else if (auto *structDecl = dyn_cast<StructDecl>(dc)) {
if (structDecl->hasClangNode())
return;
}
// Stored properties in SIL mode don't get accessors.
// But we might need to create opaque accessors for them.
if (auto sourceFile = dc->getParentSourceFile())
if (sourceFile->Kind == SourceFileKind::SIL) {
if (storage->getGetter()) {
addExpectedOpaqueAccessorsToStorage(storage, ctx);
}
return;
}
// Everything else gets mandatory accessors.
addTrivialAccessorsToStorage(storage, ctx);
}
static void synthesizeGetterBody(AccessorDecl *getter,
ASTContext &ctx) {
if (getter->hasForcedStaticDispatch()) {
synthesizeTrivialGetterBody(getter, TargetImpl::Ordinary, ctx);
return;
}
switch (getter->getStorage()->getReadImpl()) {
case ReadImplKind::Stored:
synthesizeTrivialGetterBody(getter, ctx);
return;
case ReadImplKind::Get:
llvm_unreachable("synthesizing getter that already exists?");
case ReadImplKind::Inherited:
synthesizeInheritedGetterBody(getter, ctx);
return;
case ReadImplKind::Address:
synthesizeAddressedGetterBody(getter, ctx);
return;
case ReadImplKind::Read:
synthesizeReadCoroutineGetterBody(getter, ctx);
return;
}
llvm_unreachable("bad ReadImplKind");
}
static void synthesizeSetterBody(AccessorDecl *setter,
ASTContext &ctx) {
switch (setter->getStorage()->getWriteImpl()) {
case WriteImplKind::Immutable:
llvm_unreachable("synthesizing setter from immutable storage");
case WriteImplKind::Stored:
return synthesizeTrivialSetterBody(setter, ctx);
case WriteImplKind::StoredWithObservers:
return synthesizeStoredWithObserversSetterBody(setter, ctx);
case WriteImplKind::InheritedWithObservers:
return synthesizeInheritedWithObserversSetterBody(setter, ctx);
case WriteImplKind::Set:
llvm_unreachable("synthesizing setter for unknown reason?");
case WriteImplKind::MutableAddress:
return synthesizeMutableAddressSetterBody(setter, ctx);
case WriteImplKind::Modify:
return synthesizeModifyCoroutineSetterBody(setter, ctx);
}
llvm_unreachable("bad ReadImplKind");
}
void synthesizeAccessorBody(AbstractFunctionDecl *fn, void *) {
auto *accessor = cast<AccessorDecl>(fn);
auto &ctx = accessor->getASTContext();
if (accessor->isInvalid() || ctx.hadError())
return;
switch (accessor->getAccessorKind()) {
case AccessorKind::Get:
synthesizeGetterBody(accessor, ctx);
return;
case AccessorKind::Set:
synthesizeSetterBody(accessor, ctx);
return;
case AccessorKind::Read:
synthesizeReadCoroutineBody(accessor, ctx);
return;
case AccessorKind::Modify:
synthesizeModifyCoroutineBody(accessor, ctx);
return;
case AccessorKind::WillSet:
case AccessorKind::DidSet:
case AccessorKind::Address:
case AccessorKind::MutableAddress:
break;
}
llvm_unreachable("bad synthesized function kind");
}
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;
// If we don't have an expression initializer or silgen can't assign a default
// initializer, then we can't generate a default value. An example of where
// silgen can assign a default is var x: Int? where the default is nil.
// If the variable is lazy, go ahead and give it a default value.
if (!var->getAttrs().hasAttribute<LazyAttr>() &&
!var->getParentPatternBinding()->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>.
if ((isa<OptionalType>(var->getValueInterfaceType().getPointer()) &&
!var->getParentInitializer()) ||
var->getAttrs().hasAttribute<LazyAttr>()) {
arg->setDefaultArgumentKind(DefaultArgumentKind::NilLiteral);
return;
}
// 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(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;
// Implicit, computed, and static properties are not initialized.
// The exception is lazy properties, which due to batch mode we may or
// may not have yet finalized, so they may currently be "stored" or
// "computed" in the current AST state.
if (var->isImplicit() || var->isStatic())
continue;
if (!var->hasStorage() && !var->getAttrs().hasAttribute<LazyAttr>())
continue;
// Initialized 'let' properties have storage, but don't get an argument
// to the memberwise initializer since they already have an initial
// value that cannot be overridden.
if (var->isLet() && var->getParentInitializer())
continue;
accessLevel = std::min(accessLevel, var->getFormalAccess());
tc.validateDecl(var);
auto varInterfaceType = var->getValueInterfaceType();
// If var is a lazy property, its value is provided for the underlying
// storage. We thus take an optional of the properties type. We only
// need to do this because the implicit constructor is added before all
// the properties are type checked. Perhaps init() synth should be moved
// later.
if (var->getAttrs().hasAttribute<LazyAttr>())
varInterfaceType = OptionalType::get(varInterfaceType);
// Create the parameter.
auto *arg = new (ctx)
ParamDecl(VarDecl::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 void synthesizeStubBody(AbstractFunctionDecl *fn, void *) {
auto *ctor = cast<ConstructorDecl>(fn);
auto &ctx = ctor->getASTContext();
auto unimplementedInitDecl = ctx.getUnimplementedInitializerDecl();
auto classDecl = ctor->getDeclContext()->getSelfClassDecl();
if (!unimplementedInitDecl) {
ctx.Diags.diagnose(classDecl->getLoc(),
diag::missing_unimplemented_init_runtime);
return;
}
// Create a call to Swift._unimplementedInitializer
auto loc = classDecl->getLoc();
Expr *ref = new (ctx) DeclRefExpr(unimplementedInitDecl,
DeclNameLoc(loc),
/*Implicit=*/true);
llvm::SmallString<64> buffer;
StringRef fullClassName = ctx.AllocateCopy(
(classDecl->getModuleContext()->getName().str() +
"." +
classDecl->getName().str()).toStringRef(buffer));
Expr *className = new (ctx) StringLiteralExpr(fullClassName, loc,
/*Implicit=*/true);
Expr *call = CallExpr::createImplicit(ctx, ref, { className },
{ ctx.Id_className });
ctor->setBody(BraceStmt::create(ctx, SourceLoc(),
ASTNode(call),
SourceLoc(),
/*implicit=*/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 void synthesizeDesignatedInitOverride(AbstractFunctionDecl *fn,
void *context) {
auto *ctor = cast<ConstructorDecl>(fn);
auto &ctx = ctor->getASTContext();
auto *bodyParams = ctor->getParameters();
auto *superclassCtor = (ConstructorDecl *) context;
// Reference to super.init.
auto *selfDecl = ctor->getImplicitSelfDecl();
Expr *superRef = new (ctx) SuperRefExpr(selfDecl, SourceLoc(),
/*Implicit=*/true);
Expr *ctorRef = new (ctx) UnresolvedDotExpr(superRef, SourceLoc(),
superclassCtor->getFullName(),
DeclNameLoc(),
/*Implicit=*/true);
auto ctorArgs = buildArgumentForwardingExpr(bodyParams->getArray(), ctx);
Expr *superCall =
CallExpr::create(ctx, ctorRef, ctorArgs,
superclassCtor->getFullName().getArgumentNames(), { },
/*hasTrailingClosure=*/false, /*implicit=*/true);
if (superclassCtor->hasThrows()) {
superCall = new (ctx) TryExpr(SourceLoc(), superCall, Type(),
/*implicit=*/true);
}
ctor->setBody(BraceStmt::create(ctx, SourceLoc(),
ASTNode(superCall),
SourceLoc(),
/*implicit=*/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);
decl->setInterfaceType(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;
}