//===--- 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 "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; /// 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(DC)) { ntd->addMember(D, Hint); } else if (auto *ed = dyn_cast(DC)) { ed->addMember(D, Hint); } else { assert((isa(DC) || isa(DC)) && "Unknown declcontext"); } } static ParamDecl *getParamDeclAtIndex(FuncDecl *fn, unsigned index) { return fn->getParameterLists().back()->get(index); } static VarDecl *getFirstParamDecl(FuncDecl *fn) { return getParamDeclAtIndex(fn, 0); }; static ParamDecl *buildArgument(SourceLoc loc, DeclContext *DC, StringRef name, Type type, Type interfaceType, VarDecl::Specifier specifier) { auto &context = DC->getASTContext(); auto *param = new (context) ParamDecl(specifier, SourceLoc(), SourceLoc(), Identifier(), loc, context.getIdentifier(name), type, DC); param->setImplicit(); param->setInterfaceType(interfaceType); return param; } static Type getTypeOfStorage(AbstractStorageDecl *storage, bool wantInterfaceType) { if (auto var = dyn_cast(storage)) { auto type = (wantInterfaceType ? var->getInterfaceType() : var->getType()); return type->getReferenceStorageReferent(); } auto subscript = cast(storage); auto type = subscript->getElementInterfaceType(); if (!wantInterfaceType) type = storage->getDeclContext()->mapTypeIntoContext(type); return type; } /// 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 prefix) { auto &context = storage->getASTContext(); auto subscript = dyn_cast(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); if (prefix.empty()) return indices; // Otherwise, we need to build up a new parameter list. SmallVector 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); } static AccessorDecl *createGetterPrototype(AbstractStorageDecl *storage, TypeChecker &TC) { SourceLoc loc = storage->getLoc(); // Create the parameter list for the getter. SmallVector getterParams; // The implicit 'self' argument if in a type context. if (storage->getDeclContext()->isTypeContext()) { ParamDecl *selfDecl; // For lazy properties, steal the 'self' from the initializer context. if (storage->getAttrs().hasAttribute()) { auto *varDecl = cast(storage); auto *bindingDecl = varDecl->getParentPatternBinding(); auto *bindingInit = cast( bindingDecl->getPatternEntryForVarDecl(varDecl).getInitContext()); selfDecl = bindingInit->getImplicitSelfDecl(); } else { selfDecl = ParamDecl::createSelf(loc, storage->getDeclContext(), /*isStatic*/false); } getterParams.push_back(ParameterList::create(TC.Context, selfDecl)); } // Add an index-forwarding clause. getterParams.push_back(buildIndexForwardingParamList(storage, {})); SourceLoc staticLoc; if (auto var = dyn_cast(storage)) { if (var->isStatic()) staticLoc = var->getLoc(); } auto storageInterfaceType = getTypeOfStorage(storage, true); auto getter = AccessorDecl::create( TC.Context, loc, /*AccessorKeywordLoc*/ loc, AccessorKind::Get, AddressorKind::NotAddressor, storage, staticLoc, StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, getterParams, TypeLoc::withoutLoc(storageInterfaceType), storage->getDeclContext()); getter->setImplicit(); if (storage->isGetterMutating()) getter->setSelfAccessKind(SelfAccessKind::Mutating); if (storage->isStatic()) getter->setStatic(); if (auto *overridden = storage->getOverriddenDecl()) if (auto *overriddenAccessor = overridden->getGetter()) getter->setOverriddenDecl(overriddenAccessor); return getter; } static AccessorDecl *createSetterPrototype(AbstractStorageDecl *storage, ParamDecl *&valueDecl, TypeChecker &TC) { SourceLoc loc = storage->getLoc(); // Create the parameter list for the setter. SmallVector params; bool isStatic = storage->isStatic(); bool isMutating = storage->isSetterMutating(); // The implicit 'self' argument if in a type context. if (storage->getDeclContext()->isTypeContext()) { params.push_back(ParameterList::createSelf(loc, storage->getDeclContext(), /*isStatic*/isStatic, /*isInOut*/isMutating)); } // Add a "(value : T, indices...)" argument list. auto storageType = getTypeOfStorage(storage, false); auto storageInterfaceType = getTypeOfStorage(storage, true); valueDecl = buildArgument(storage->getLoc(), storage->getDeclContext(), "value", storageType, storageInterfaceType, VarDecl::Specifier::Default); params.push_back(buildIndexForwardingParamList(storage, valueDecl)); Type setterRetTy = TupleType::getEmpty(TC.Context); auto setter = AccessorDecl::create( TC.Context, loc, /*AccessorKeywordLoc*/ SourceLoc(), AccessorKind::Set, AddressorKind::NotAddressor, storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, params, TypeLoc::withoutLoc(setterRetTy), storage->getDeclContext()); setter->setImplicit(); if (isMutating) setter->setSelfAccessKind(SelfAccessKind::Mutating); if (isStatic) setter->setStatic(); if (auto *overridden = storage->getOverriddenDecl()) { auto *overriddenAccessor = overridden->getSetter(); if (overriddenAccessor && overridden->isSetterAccessibleFrom(storage->getDeclContext())) { setter->setOverriddenDecl(overriddenAccessor); } } return setter; } // True if the storage is dynamic or imported from Objective-C. In these cases, // we need to emit a static materializeForSet thunk that dynamically dispatches // to 'get' and 'set', rather than the normal dynamically dispatched // materializeForSet that peer dispatches to 'get' and 'set'. static bool needsDynamicMaterializeForSet(AbstractStorageDecl *storage) { return storage->isDynamic() || storage->hasClangNode(); } /// 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(FuncDecl *accessor, AbstractStorageDecl *storage, TypeChecker &TC) { auto *DC = storage->getDeclContext(); auto *nominalDecl = DC->getAsNominalTypeOrNominalTypeExtensionContext(); // Global variable accessors are not @_transparent. if (!nominalDecl) return; // Accessors for resilient properties are not @_transparent. if (storage->isResilient()) 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(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(nominalDecl)) if (classDecl->checkObjCAncestry() != ObjCClassKind::NonObjC) return; accessor->getAttrs().add(new (TC.Context) TransparentAttr(IsImplicit)); } static AccessorDecl * createMaterializeForSetPrototype(AbstractStorageDecl *storage, FuncDecl *getter, FuncDecl *setter, TypeChecker &TC) { auto &ctx = storage->getASTContext(); SourceLoc loc = storage->getLoc(); // Create the parameter list: SmallVector params; // - The implicit 'self' argument if in a type context. auto DC = storage->getDeclContext(); if (DC->isTypeContext()) params.push_back(ParameterList::createSelf(loc, DC, /*isStatic*/false)); // - The buffer parameter, (buffer: Builtin.RawPointer, // inout storage: Builtin.UnsafeValueBuffer, // indices...). ParamDecl *bufferElements[] = { buildArgument(loc, DC, "buffer", ctx.TheRawPointerType, ctx.TheRawPointerType, VarDecl::Specifier::Default), buildArgument(loc, DC, "callbackStorage", ctx.TheUnsafeValueBufferType, ctx.TheUnsafeValueBufferType, VarDecl::Specifier::InOut)}; params.push_back(buildIndexForwardingParamList(storage, bufferElements)); // The accessor returns (temporary: Builtin.RawPointer, // callback: Optional), // where the first pointer is the materialized address and the // second is the address of an optional callback. TupleTypeElt retElts[] = { { ctx.TheRawPointerType }, { OptionalType::get(ctx.TheRawPointerType) }, }; Type retTy = TupleType::get(retElts, ctx); // Accessors of generic subscripts get a copy of the subscript's // generic parameter list, because they're not nested inside the // subscript. GenericParamList *genericParams = nullptr; if (auto *subscript = dyn_cast(storage)) genericParams = subscript->getGenericParams(); auto *materializeForSet = AccessorDecl::create( ctx, loc, /*AccessorKeywordLoc=*/SourceLoc(), AccessorKind::MaterializeForSet, AddressorKind::NotAddressor, storage, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), (genericParams ? genericParams->clone(DC) : nullptr), params, TypeLoc::withoutLoc(retTy), DC); materializeForSet->setImplicit(); // Open-code the setMutating() calculation since we might run before // the setter has been type checked. Type contextTy = DC->getDeclaredInterfaceType(); if (contextTy && !contextTy->hasReferenceSemantics()) { bool hasMutatingSetter = !setter->getAttrs().hasAttribute() && storage->isSetterMutating(); bool hasMutatingGetter = getter->getAttrs().hasAttribute(); if (hasMutatingSetter || hasMutatingGetter) materializeForSet->setSelfAccessKind(SelfAccessKind::Mutating); } materializeForSet->setStatic(storage->isStatic()); // materializeForSet is final if the storage is. if (storage->isFinal()) makeFinal(ctx, materializeForSet); if (auto *overridden = storage->getOverriddenDecl()) { auto *overriddenAccessor = overridden->getMaterializeForSetFunc(); if (overriddenAccessor && !overriddenAccessor->hasForcedStaticDispatch() && overridden->isSetterAccessibleFrom(storage->getDeclContext())) { materializeForSet->setOverriddenDecl(overriddenAccessor); } } // If the storage is dynamic or ObjC-native, we can't add a dynamically- // dispatched method entry for materializeForSet, so force it to be // statically dispatched. ("final" would be inappropriate because the // property can still be overridden.) if (needsDynamicMaterializeForSet(storage)) materializeForSet->setForcedStaticDispatch(true); // Make sure materializeForSet is available enough to access // the storage (and its getters/setters if it has them). SmallVector asAvailableAs; asAvailableAs.push_back(storage); if (FuncDecl *getter = storage->getGetter()) { asAvailableAs.push_back(getter); } if (FuncDecl *setter = storage->getSetter()) { asAvailableAs.push_back(setter); } maybeMarkTransparent(materializeForSet, storage, TC); AvailabilityInference::applyInferredAvailableAttrs(materializeForSet, asAvailableAs, ctx); TC.Context.addSynthesizedDecl(materializeForSet); TC.DeclsToFinalize.insert(materializeForSet); return materializeForSet; } static void convertStoredVarInProtocolToComputed(VarDecl *VD, TypeChecker &TC) { auto *Get = createGetterPrototype(VD, TC); // Okay, we have the getter; make the VD computed. VD->setAccessors(AbstractStorageDecl::Computed, SourceLoc(), {Get}, SourceLoc()); // We've added some members to our containing class, add them to the members // list. addMemberToContextIfNeeded(Get, VD->getDeclContext(), VD); } /// Build an expression that evaluates the specified parameter list as a tuple /// or paren expr, suitable for use in an applyexpr. /// /// NOTE: This returns null if a varargs parameter exists in the list, as it /// cannot be forwarded correctly yet. /// static Expr *buildArgumentForwardingExpr(ArrayRef params, ASTContext &ctx) { SmallVector labels; SmallVector labelLocs; SmallVector args; for (auto param : params) { // We cannot express how to forward variadic parameters yet. if (param->isVariadic()) return nullptr; Expr *ref = new (ctx) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true); if (param->isInOut()) ref = new (ctx) InOutExpr(SourceLoc(), ref, Type(), /*isImplicit=*/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()) { 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->getParameterLists().back()->getArray(); auto accessorKind = accessor->getAccessorKind(); // Ignore the value/buffer parameter. if (accessorKind != AccessorKind::Get) params = params.slice(1); // Ignore the materializeForSet callback storage parameter. if (accessorKind == AccessorKind::MaterializeForSet) params = params.slice(1); // Okay, everything else should be forwarded, build the expression. auto result = buildArgumentForwardingExpr(params, ctx); assert(result && "FIXME: Cannot forward varargs"); 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, TypeChecker &TC) { switch (selfAccessorKind) { case SelfAccessorKind::Peer: return new (TC.Context) DeclRefExpr(selfDecl, DeclNameLoc(), IsImplicit); case SelfAccessorKind::Super: return new (TC.Context) SuperRefExpr(selfDecl, SourceLoc(), IsImplicit); } llvm_unreachable("bad self access kind"); } namespace { /// A simple helper interface for buildStorageReference. class StorageReferenceContext { StorageReferenceContext(const StorageReferenceContext &) = delete; public: StorageReferenceContext() = default; virtual ~StorageReferenceContext() = default; /// Returns the declaration of the entity to use as the base of /// the access, or nil if no base is required. virtual VarDecl *getSelfDecl() const = 0; /// Returns an expression producing the index value, assuming that /// the storage is a subscript declaration. virtual Expr *getIndexRefExpr(ASTContext &ctx, SubscriptDecl *subscript) const = 0; }; /// A reference to storage from within an accessor. class AccessorStorageReferenceContext : public StorageReferenceContext { AccessorDecl *Accessor; public: AccessorStorageReferenceContext(AccessorDecl *accessor) : Accessor(accessor) {} ~AccessorStorageReferenceContext() override = default; VarDecl *getSelfDecl() const override { return Accessor->getImplicitSelfDecl(); } Expr *getIndexRefExpr(ASTContext &ctx, SubscriptDecl *subscript) const override { return buildSubscriptIndexReference(ctx, Accessor); } }; } // end anonymous namespace /// Build an l-value for the storage of a declaration. static Expr *buildStorageReference( const StorageReferenceContext &referenceContext, AbstractStorageDecl *storage, AccessSemantics semantics, SelfAccessorKind selfAccessorKind, TypeChecker &TC) { ASTContext &ctx = TC.Context; VarDecl *selfDecl = referenceContext.getSelfDecl(); if (!selfDecl) { return new (ctx) DeclRefExpr(storage, DeclNameLoc(), IsImplicit, semantics); } // If we should use a super access if applicable, and we have an // overridden decl, then use ordinary access to it. if (selfAccessorKind == SelfAccessorKind::Super) { if (auto overridden = storage->getOverriddenDecl()) { storage = overridden; semantics = AccessSemantics::Ordinary; } else { selfAccessorKind = SelfAccessorKind::Peer; } } Expr *selfDRE = buildSelfReference(selfDecl, selfAccessorKind, TC); if (auto subscript = dyn_cast(storage)) { Expr *indices = referenceContext.getIndexRefExpr(ctx, subscript); return SubscriptExpr::create(ctx, selfDRE, indices, storage, IsImplicit, semantics); } // This is a potentially polymorphic access, which is unnecessary; // however, it shouldn't be problematic because any overrides // should also redefine materializeForSet. return new (ctx) MemberRefExpr(selfDRE, SourceLoc(), storage, DeclNameLoc(), IsImplicit, semantics); } static Expr *buildStorageReference(AccessorDecl *accessor, AbstractStorageDecl *storage, AccessSemantics semantics, SelfAccessorKind selfAccessorKind, TypeChecker &TC) { return buildStorageReference(AccessorStorageReferenceContext(accessor), storage, semantics, selfAccessorKind, TC); } /// 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, TypeChecker &TC) { return buildStorageReference(accessor, storage, AccessSemantics::DirectToStorage, SelfAccessorKind::Super, TC); } /// Look up the NSCopying protocol from the Foundation module, if present. /// Otherwise return null. static ProtocolDecl *getNSCopyingProtocol(TypeChecker &TC, DeclContext *DC) { ASTContext &ctx = TC.Context; auto foundation = ctx.getLoadedModule(ctx.Id_Foundation); if (!foundation) return nullptr; SmallVector results; DC->lookupQualified(ModuleType::get(foundation), ctx.getSwiftId(KnownFoundationEntity::NSCopying), NL_QualifiedDefault | NL_KnownNonCascadingDependency, /*typeResolver=*/nullptr, results); if (results.size() != 1) return nullptr; return dyn_cast(results.front()); } /// 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, TypeChecker &TC) { auto &Ctx = TC.Context; // We support @NSCopying on class types (which conform to NSCopying), // protocols which conform, and option types thereof. Type UnderlyingType = VD->getType()->getReferenceStorageReferent(); bool isOptional = false; if (Type optionalEltTy = UnderlyingType->getOptionalObjectType()) { UnderlyingType = optionalEltTy; isOptional = true; } // The element type must conform to NSCopying. If not, emit an error and just // recovery by synthesizing without the copy call. auto *CopyingProto = getNSCopyingProtocol(TC, VD->getDeclContext()); if (!CopyingProto || !TC.conformsToProtocol(UnderlyingType, CopyingProto, VD->getDeclContext(), None)) { TC.diagnose(VD->getLoc(), diag::nscopying_doesnt_conform); 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='' // (call_expr type='' // (unresolved_dot_expr type='' field 'copy' // "Val") // (paren_expr type='' // (nil_literal_expr type='')))) 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, SmallVectorImpl &body, TypeChecker &TC) { // 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(storage)) { if (property->getAttrs().hasAttribute()) value = synthesizeCopyWithZoneCall(value, property, TC); } // 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, AccessSemantics::DirectToStorage, SelfAccessorKind::Super, TC); body.push_back(new (TC.Context) AssignExpr(dest, SourceLoc(), value, IsImplicit)); } /// 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 synthesizeTrivialGetter(AccessorDecl *getter, AbstractStorageDecl *storage, TypeChecker &TC) { auto &ctx = TC.Context; Expr *result = createPropertyLoadOrCallSuperclassGetter(getter, storage, TC); ASTNode returnStmt = new (ctx) ReturnStmt(SourceLoc(), result, IsImplicit); SourceLoc loc = storage->getLoc(); getter->setBody(BraceStmt::create(ctx, loc, returnStmt, loc, true)); TC.Context.addSynthesizedDecl(getter); TC.DeclsToFinalize.insert(getter); } /// Synthesize the body of a trivial setter. static void synthesizeTrivialSetter(AccessorDecl *setter, AbstractStorageDecl *storage, VarDecl *valueVar, TypeChecker &TC) { auto &ctx = TC.Context; SourceLoc loc = storage->getLoc(); auto *valueDRE = new (ctx) DeclRefExpr(valueVar, DeclNameLoc(), IsImplicit); SmallVector setterBody; createPropertyStoreOrCallSuperclassSetter(setter, valueDRE, storage, setterBody, TC); setter->setBody(BraceStmt::create(ctx, loc, setterBody, loc, true)); TC.Context.addSynthesizedDecl(setter); TC.DeclsToFinalize.insert(setter); } /// Does a storage decl currently lacking accessor functions require a /// setter to be synthesized? static bool doesStorageNeedSetter(AbstractStorageDecl *storage) { assert(!storage->hasAccessorFunctions()); switch (storage->getStorageKind()) { // Add a setter to a stored variable unless it's a let. case AbstractStorageDecl::Stored: return !cast(storage)->isLet(); // Addressed storage gets a setter if it has a mutable addressor. case AbstractStorageDecl::Addressed: return storage->getMutableAddressor() != nullptr; // These should already have accessor functions. case AbstractStorageDecl::StoredWithTrivialAccessors: case AbstractStorageDecl::StoredWithObservers: case AbstractStorageDecl::InheritedWithObservers: case AbstractStorageDecl::AddressedWithTrivialAccessors: case AbstractStorageDecl::AddressedWithObservers: case AbstractStorageDecl::ComputedWithMutableAddress: llvm_unreachable("already has accessor functions"); case AbstractStorageDecl::Computed: llvm_unreachable("not stored"); } llvm_unreachable("bad storage kind"); } /// Add trivial accessors to a Stored or Addressed property. static void addTrivialAccessorsToStorage(AbstractStorageDecl *storage, TypeChecker &TC) { assert(!storage->hasAccessorFunctions() && "already has accessors?"); assert(!storage->getAttrs().hasAttribute()); assert(!storage->getAttrs().hasAttribute()); auto *DC = storage->getDeclContext(); // Create the getter. AccessorDecl *getter = createGetterPrototype(storage, TC); // Create the setter. AccessorDecl *setter = nullptr; ParamDecl *setterValueParam = nullptr; if (doesStorageNeedSetter(storage)) setter = createSetterPrototype(storage, setterValueParam, TC); // Okay, we have both the getter and setter. Set them in VD. storage->addTrivialAccessors(getter, setter, nullptr); // Synthesize the body of the getter. synthesizeTrivialGetter(getter, storage, TC); maybeMarkTransparent(getter, storage, TC); if (setter) { // Synthesize the body of the setter. synthesizeTrivialSetter(setter, storage, setterValueParam, TC); maybeMarkTransparent(setter, storage, TC); } // We've added some members to our containing context, add them to // the right list. addMemberToContextIfNeeded(getter, DC, storage); if (setter) addMemberToContextIfNeeded(setter, DC, getter); maybeAddMaterializeForSet(storage, TC); } /// Add a trivial setter and materializeForSet to a /// ComputedWithMutableAddress storage decl. void swift:: synthesizeSetterForMutableAddressedStorage(AbstractStorageDecl *storage, TypeChecker &TC) { auto setter = storage->getSetter(); assert(setter); if (setter->getBody()) return; assert(storage->getStorageKind() == AbstractStorageDecl::ComputedWithMutableAddress); // Synthesize the body of the setter. VarDecl *valueParamDecl = getFirstParamDecl(setter); synthesizeTrivialSetter(setter, storage, valueParamDecl, TC); maybeMarkTransparent(setter, storage, TC); } /// Add a materializeForSet accessor to the given declaration. static FuncDecl *addMaterializeForSet(AbstractStorageDecl *storage, TypeChecker &TC) { if (TC.Context.getOptionalDecl() == nullptr) { TC.diagnose(storage->getStartLoc(), diag::optional_intrinsics_not_found); return nullptr; } auto materializeForSet = createMaterializeForSetPrototype( storage, storage->getGetter(), storage->getSetter(), TC); addMemberToContextIfNeeded(materializeForSet, storage->getDeclContext(), storage->getSetter()); storage->setMaterializeForSetFunc(materializeForSet); return materializeForSet; } static void convertNSManagedStoredVarToComputed(VarDecl *VD, TypeChecker &TC) { assert(VD->getStorageKind() == AbstractStorageDecl::Stored); // Create the getter. auto *Get = createGetterPrototype(VD, TC); // Create the setter. ParamDecl *SetValueDecl = nullptr; auto *Set = createSetterPrototype(VD, SetValueDecl, TC); // Okay, we have both the getter and setter. Set them in VD. VD->setAccessors(VarDecl::Computed, SourceLoc(), {Get, Set}, SourceLoc()); // We've added some members to our containing class/extension, add them to // the members list. addMemberToContextIfNeeded(Get, VD->getDeclContext(), VD); addMemberToContextIfNeeded(Set, VD->getDeclContext(), Get); maybeAddMaterializeForSet(VD, TC); } /// 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) { // If the decl is stored, convert it to StoredWithTrivialAccessors // by synthesizing the full set of accessors. if (!storage->hasAccessorFunctions()) { // Don't do this if the declaration is lazy or NSManaged. // This must be a re-entrant attempt to synthesize accessors // before validateDecl has finished. if (storage->getAttrs().hasAttribute() || storage->getAttrs().hasAttribute()) return; addTrivialAccessorsToStorage(storage, *this); } // @objc protocols don't need a materializeForSet since ObjC doesn't // have that concept. bool wantMaterializeForSet = !requirement->isObjC() && requirement->getSetter(); // If we want wantMaterializeForSet, create it now. if (wantMaterializeForSet && !storage->getMaterializeForSetFunc()) addMaterializeForSet(storage, *this); } /// Given a VarDecl with a willSet: and/or didSet: specifier, synthesize the /// (trivial) getter and the setter, which calls these. void swift::synthesizeObservingAccessors(VarDecl *VD, TypeChecker &TC) { assert(VD->hasObservers()); assert(VD->getGetter() && VD->getSetter()); auto &Ctx = VD->getASTContext(); SourceLoc Loc = VD->getLoc(); // We have to be paranoid about the accessors already having bodies // because there might be an (invalid) existing definition. // The getter is always trivial: just perform a (direct!) load of storage, or // a call of a superclass getter if this is an override. auto *Get = VD->getGetter(); if (!Get->hasBody()) { synthesizeTrivialGetter(Get, VD, TC); maybeMarkTransparent(Get, VD, TC); } // Okay, the getter is done, create the setter now. Start by finding the // decls for 'self' and 'value'. auto *Set = VD->getSetter(); if (Set->hasBody()) return; auto *SelfDecl = Set->getImplicitSelfDecl(); VarDecl *ValueDecl = Set->getParameterLists().back()->get(0); // The setter loads the oldValue, invokes willSet with the incoming value, // does a direct store, then invokes didSet with the oldValue. SmallVector 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, TC); OldValue = new (Ctx) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Let, /*IsCaptureList*/false, SourceLoc(), Ctx.getIdentifier("tmp"), Type(), Set); OldValue->setImplicit(); auto *tmpPattern = new (Ctx) NamedPattern(OldValue, /*implicit*/ true); auto tmpPBD = PatternBindingDecl::create(Ctx, SourceLoc(), StaticSpellingKind::None, SourceLoc(), tmpPattern, OldValueExpr, Set); tmpPBD->setImplicit(); 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() })); // Make sure the didSet/willSet accessors are marked final if in a class. if (!willSet->isFinal() && VD->getDeclContext()->getAsClassOrClassExtensionContext()) makeFinal(Ctx, willSet); } // Create an assignment into the storage or call to superclass setter. auto *ValueDRE = new (Ctx) DeclRefExpr(ValueDecl, DeclNameLoc(), true); createPropertyStoreOrCallSuperclassSetter(Set, ValueDRE, VD, SetterBody, TC); // 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() })); // Make sure the didSet/willSet accessors are marked final if in a class. if (!didSet->isFinal() && VD->getDeclContext()->getAsClassOrClassExtensionContext()) makeFinal(Ctx, didSet); } Set->setBody(BraceStmt::create(Ctx, Loc, SetterBody, Loc, true)); } 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 walkToExprPre(Expr *E) override { // If we find a closure, update its declcontext and do *not* walk into it. if (auto CE = dyn_cast(E)) { CE->setParent(NewDC); return { false, E }; } if (auto CLE = dyn_cast(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); } } return { true, E }; } /// We don't want to recurse into declarations or statements. bool walkToDeclPre(Decl *) override { return false; } std::pair walkToStmtPre(Stmt *S) override { return {false,S}; } }; } // end anonymous namespace /// Synthesize the getter for a lazy property with the specified storage /// vardecl. static FuncDecl *completeLazyPropertyGetter(VarDecl *VD, VarDecl *Storage, TypeChecker &TC) { auto &Ctx = VD->getASTContext(); // 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 = <> // storage = tmp2 // return tmp2 // } auto *Get = VD->getGetter(); SmallVector 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"), Type(), Get); Tmp1VD->setImplicit(); auto *Tmp1PBDPattern = new (Ctx) NamedPattern(Tmp1VD, /*implicit*/true); auto *Tmp1Init = createPropertyLoadOrCallSuperclassGetter(Get, Storage, TC); auto *Tmp1PBD = PatternBindingDecl::create(Ctx, /*StaticLoc*/SourceLoc(), StaticSpellingKind::None, /*VarLoc*/SourceLoc(), 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"), VD->getType(), Get); 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); PBD->setInit(entryIndex, nullptr); PBD->setInitializerChecked(entryIndex); // Recontextualize any closure declcontexts nested in the initializer to // realize that they are in the getter function. InitValue->walk(RecontextualizeClosures(Get)); Pattern *Tmp2PBDPattern = new (Ctx) NamedPattern(Tmp2VD, /*implicit*/true); Tmp2PBDPattern = new (Ctx) TypedPattern(Tmp2PBDPattern, TypeLoc::withoutLoc(VD->getType()), /*implicit*/true); auto *Tmp2PBD = PatternBindingDecl::create(Ctx, /*StaticLoc*/SourceLoc(), StaticSpellingKind::None, InitValue->getStartLoc(), Tmp2PBDPattern, InitValue, Get); 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, Body, TC); // 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)); return Get; } void TypeChecker::completePropertyBehaviorStorage(VarDecl *VD, VarDecl *BehaviorStorage, FuncDecl *DefaultInitStorage, FuncDecl *ParamInitStorage, Type SelfTy, Type StorageTy, NormalProtocolConformance *BehaviorConformance, SubstitutionMap interfaceMap, SubstitutionMap contextMap) { assert(BehaviorStorage); assert((bool)DefaultInitStorage != (bool)ParamInitStorage); // Substitute the storage type into the conforming context. auto SubstStorageInterfaceTy = StorageTy.subst(interfaceMap); assert(SubstStorageInterfaceTy && "storage type substitution failed?!"); auto SubstStorageContextTy = StorageTy.subst(contextMap); assert(SubstStorageContextTy && "storage type substitution failed?!"); auto DC = VD->getDeclContext(); SmallString<64> NameBuf = VD->getName().str(); NameBuf += ".storage"; auto StorageName = Context.getIdentifier(NameBuf); auto storageSpecifier = BehaviorStorage->isSettable(DC) ? VarDecl::Specifier::Var : VarDecl::Specifier::Let; auto *Storage = new (Context) VarDecl( /*IsStatic*/VD->isStatic(), storageSpecifier, /*IsCaptureList*/false, VD->getLoc(), StorageName, SubstStorageContextTy, DC); Storage->setInterfaceType(SubstStorageInterfaceTy); Storage->setUserAccessible(false); // Mark the vardecl to be final, implicit, and private. In a class, this // prevents it from being dynamically dispatched. if (VD->getDeclContext()->getAsClassOrClassExtensionContext()) makeFinal(Context, Storage); Storage->setImplicit(); Storage->setAccess(AccessLevel::Private); Storage->setSetterAccess(AccessLevel::Private); addMemberToContextIfNeeded(Storage, DC); // Initialize the storage immediately, if we can. Expr *InitStorageExpr = nullptr; auto Method = DefaultInitStorage ? DefaultInitStorage : ParamInitStorage; auto SpecializeInitStorage = ConcreteDeclRef(Method, contextMap); if (DefaultInitStorage || (ParamInitStorage && VD->getParentInitializer())) { // Build the initializer expression, 'Self.initStorage()', using the // conformance. auto SelfTypeRef = TypeExpr::createImplicit(SelfTy, Context); auto InitStorageRef = new (Context) DeclRefExpr(SpecializeInitStorage, DeclNameLoc(), /*implicit*/ true); auto InitStorageMethodTy = FunctionType::get(Context.TheEmptyTupleType, SubstStorageContextTy); auto InitStorageRefTy = FunctionType::get(SelfTypeRef->getType(), InitStorageMethodTy); InitStorageRef->setType(InitStorageRefTy); auto SelfApply = new (Context) DotSyntaxCallExpr(InitStorageRef, SourceLoc(), SelfTypeRef); SelfApply->setImplicit(); SelfApply->setType(InitStorageMethodTy); SelfApply->setThrows(false); SmallVector InitStorageArgs; SmallVector InitStorageArgLabels; if (ParamInitStorage) { // Claim the var initializer as the parameter to the `initStorage` // method. auto InitValue = VD->getParentInitializer(); auto PBD = VD->getParentPatternBinding(); unsigned entryIndex = PBD->getPatternEntryIndexForVarDecl(VD); PBD->setInit(entryIndex, nullptr); PBD->setInitializerChecked(entryIndex); // Recontextualize any closure declcontexts nested in the initializer to // realize that they are in the initialization context. InitValue->walk(RecontextualizeClosures(DC)); // Coerce to the property type. auto PropertyType = Type(contextMap.getGenericSignature()->getGenericParams()[1]) .subst(contextMap); InitValue = new (Context) CoerceExpr(InitValue, SourceLoc(), TypeLoc::withoutLoc(PropertyType)); // Type-check the expression. typeCheckExpression(InitValue, DC); InitStorageArgs.push_back(InitValue); InitStorageArgLabels.push_back(Identifier()); } auto InitStorageExpr = CallExpr::createImplicit(Context,SelfApply, InitStorageArgs, InitStorageArgLabels); InitStorageExpr->setType(SubstStorageContextTy); InitStorageExpr->setThrows(false); } else { // Save the storage property and the initStorage reference for later. // We'll leave it to DI analysis to insert the initializer call at the // right place. auto *Behavior = VD->getMutableBehavior(); Behavior->StorageDecl = Storage; Behavior->InitStorageDecl = SpecializeInitStorage; } // Create the pattern binding decl for the storage decl. This will get // default initialized using the protocol's initStorage() method. Pattern *PBDPattern = new (Context) NamedPattern(Storage, /*implicit*/true); PBDPattern = new (Context) TypedPattern(PBDPattern, TypeLoc::withoutLoc(SubstStorageContextTy), /*implicit*/true); auto *PBD = PatternBindingDecl::create(Context, /*staticloc*/SourceLoc(), VD->getParentPatternBinding()->getStaticSpelling(), /*varloc*/VD->getLoc(), PBDPattern, /*init*/InitStorageExpr, VD->getDeclContext()); PBD->setImplicit(); PBD->setInitializerChecked(0); addMemberToContextIfNeeded(PBD, VD->getDeclContext(), VD); // Add accessors to the storage, since we'll need them to satisfy the // conformance requirements. addTrivialAccessorsToStorage(Storage, *this); // FIXME: Hack to eliminate spurious diagnostics. if (BehaviorStorage->isStatic() != Storage->isStatic()) return; // Add the witnesses to the conformance. recordKnownWitness(BehaviorConformance, BehaviorStorage, Storage); recordKnownWitness(BehaviorConformance, BehaviorStorage->getGetter(), Storage->getGetter()); if (BehaviorStorage->isSettable(DC)) recordKnownWitness(BehaviorConformance, BehaviorStorage->getSetter(), Storage->getSetter()); } void TypeChecker::completePropertyBehaviorParameter(VarDecl *VD, FuncDecl *BehaviorParameter, NormalProtocolConformance *BehaviorConformance, SubstitutionMap interfaceMap, SubstitutionMap contextMap) { // Create a method to witness the requirement. auto DC = VD->getDeclContext(); SmallString<64> NameBuf = VD->getName().str(); NameBuf += ".parameter"; auto ParameterBaseName = Context.getIdentifier(NameBuf); // Substitute the requirement type into the conforming context. auto ParameterTy = BehaviorParameter->getInterfaceType() ->castTo() ->getResult(); GenericSignature *genericSig = nullptr; GenericEnvironment *genericEnv = nullptr; auto SubstInterfaceTy = ParameterTy.subst(interfaceMap); assert(SubstInterfaceTy && "storage type substitution failed?!"); auto SubstBodyResultTy = SubstInterfaceTy->castTo() ->getResult(); // Add the Self type back to the interface and context types. if (DC->isTypeContext()) { if (DC->isGenericContext()) { genericSig = DC->getGenericSignatureOfContext(); genericEnv = DC->getGenericEnvironmentOfContext(); SubstInterfaceTy = GenericFunctionType::get(genericSig, DC->getSelfInterfaceType(), SubstInterfaceTy, AnyFunctionType::ExtInfo()); } else { SubstInterfaceTy = FunctionType::get(DC->getSelfInterfaceType(), SubstInterfaceTy); } } // Borrow the parameters from the requirement declaration. SmallVector ParamLists; if (DC->isTypeContext()) { auto self = ParamDecl::createSelf(SourceLoc(), DC); ParamLists.push_back(ParameterList::create(Context, SourceLoc(), self, SourceLoc())); ParamLists.back()->get(0)->setImplicit(); } assert(BehaviorParameter->getParameterLists().size() == 2); SmallVector Params; SmallVector NameComponents; auto *DeclaredParams = BehaviorParameter->getParameterList(1); for (unsigned i : indices(*DeclaredParams)) { auto declaredParam = DeclaredParams->get(i); auto declaredParamTy = declaredParam->getInterfaceType(); auto interfaceTy = declaredParamTy.subst(interfaceMap); assert(interfaceTy); auto contextTy = declaredParamTy.subst(contextMap); assert(contextTy); auto declaredSpecifier = declaredParam->getSpecifier(); SmallString<64> ParamNameBuf; { llvm::raw_svector_ostream names(ParamNameBuf); names << "%arg." << i; } auto param = new (Context) ParamDecl( declaredSpecifier, SourceLoc(), SourceLoc(), Identifier(), SourceLoc(), Context.getIdentifier(ParamNameBuf), contextTy, DC); param->setInterfaceType(interfaceTy); param->setImplicit(); Params.push_back(param); NameComponents.push_back(Identifier()); } ParamLists.push_back(ParameterList::create(Context, Params)); auto *Parameter = FuncDecl::create(Context, /*StaticLoc=*/SourceLoc(), StaticSpellingKind::None, /*FuncLoc=*/SourceLoc(), DeclName(Context, ParameterBaseName, NameComponents), /*NameLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*GenericParams=*/nullptr, ParamLists, TypeLoc::withoutLoc(SubstBodyResultTy), DC); Parameter->setInterfaceType(SubstInterfaceTy); Parameter->setGenericEnvironment(genericEnv); Parameter->setValidationStarted(); // Mark the method to be final, implicit, and private. In a class, this // prevents it from being dynamically dispatched. if (DC->getAsClassOrClassExtensionContext()) makeFinal(Context, Parameter); Parameter->setImplicit(); Parameter->setAccess(AccessLevel::Private); // Recontextualize any closure declcontexts nested in the initializer to // realize that they are in the parameter function. assert(VD->getBehavior()->Param); VD->getBehavior()->Param->walk(RecontextualizeClosures(Parameter)); // Apply and return the closure in the function context. SmallVector argRefs; SmallVector argNames; for (unsigned i : indices(Params)) { auto param = Params[i]; auto expr = new (Context) DeclRefExpr(param, DeclNameLoc(), /*implicit*/ true); argRefs.push_back(expr); argNames.push_back(DeclaredParams->get(i)->getName()); } auto apply = CallExpr::createImplicit(Context, VD->getBehavior()->Param, argRefs, argNames); // Return the expression value. auto Ret = new (Context) ReturnStmt(SourceLoc(), apply, /*implicit*/ true); auto Body = BraceStmt::create(Context, SourceLoc(), ASTNode(Ret), SourceLoc(), /*implicit*/ true); Parameter->setBody(Body); typeCheckDecl(Parameter); addMemberToContextIfNeeded(Parameter, DC); // Add the witnesses to the conformance. recordKnownWitness(BehaviorConformance, BehaviorParameter, Parameter); } void TypeChecker::completePropertyBehaviorAccessors(VarDecl *VD, VarDecl *ValueImpl, Type valueTy, SubstitutionMap SelfInterfaceSubs, SubstitutionMap SelfContextSubs) { auto selfGenericParamTy = Type(GenericTypeParamType::get(0, 0, Context)); auto selfTy = selfGenericParamTy.subst(SelfContextSubs); auto selfIfaceTy = selfGenericParamTy.subst(SelfInterfaceSubs); SmallVector bodyStmts; auto makeSelfExpr = [&](FuncDecl *fromAccessor, FuncDecl *toAccessor) -> Expr * { Expr *selfExpr; if (VD->getDeclContext()->isTypeContext()) { ConcreteDeclRef selfRef = fromAccessor->getImplicitSelfDecl(); selfExpr = new (Context) DeclRefExpr(selfRef, DeclNameLoc(), /*implicit*/ true); } else { // self is the empty tuple outside of a type. selfExpr = TupleExpr::createEmpty(Context, SourceLoc(), SourceLoc(), /*implicit*/ true); } // If forwarding from a nonmutating to a mutating accessor, we need to put // `self` in a mutable temporary. auto fromMutating = VD->getDeclContext()->isTypeContext() && fromAccessor->getImplicitSelfDecl()->isSettable(fromAccessor); if (!fromMutating && toAccessor->getImplicitSelfDecl()->isSettable(toAccessor)) { selfExpr->setType(selfTy); auto var = new (Context) VarDecl(/*IsStatic*/false, VarDecl::Specifier::Var, /*IsCaptureList*/false, SourceLoc(), Context.getIdentifier("tempSelf"), selfTy, fromAccessor); var->setInterfaceType(selfIfaceTy); auto varPat = new (Context) NamedPattern(var); auto pbd = PatternBindingDecl::create(Context, SourceLoc(), StaticSpellingKind::None, SourceLoc(), varPat, selfExpr, fromAccessor); bodyStmts.push_back(var); bodyStmts.push_back(pbd); selfExpr = new (Context) DeclRefExpr(var, DeclNameLoc(), /*implicit*/ true); } assert((!fromMutating || toAccessor->getImplicitSelfDecl()->isSettable(toAccessor)) && "can't forward from mutating to nonmutating"); if (!toAccessor->isMutating()) { selfExpr->setType(selfTy); } else { // Access the base as inout if the accessor is mutating. auto lvTy = LValueType::get(selfTy); selfExpr->setType(lvTy); selfExpr->propagateLValueAccessKind(AccessKind::ReadWrite); selfExpr = new (Context) InOutExpr(SourceLoc(), selfExpr, selfTy, /*implicit*/ true); } return selfExpr; }; { auto getter = VD->getGetter(); assert(getter); Expr *selfExpr = makeSelfExpr(getter, ValueImpl->getGetter()); auto implRef = ConcreteDeclRef(ValueImpl, SelfContextSubs); auto implMemberExpr = new (Context) MemberRefExpr(selfExpr, SourceLoc(), implRef, DeclNameLoc(), /*implicit*/ true); Expr *returnExpr; if (ValueImpl->isSettable(VD->getDeclContext())) { auto valueLVTy = LValueType::get(valueTy); implMemberExpr->setType(valueLVTy); implMemberExpr->propagateLValueAccessKind(AccessKind::Read); returnExpr = new (Context) LoadExpr(implMemberExpr, valueTy); returnExpr->setImplicit(); } else { implMemberExpr->setType(valueTy); returnExpr = implMemberExpr; } auto returnStmt = new (Context) ReturnStmt(SourceLoc(), returnExpr, /*implicit*/ true); bodyStmts.push_back(returnStmt); auto body = BraceStmt::create(Context, SourceLoc(), bodyStmts, SourceLoc(), /*implicit*/ true); getter->setBody(body); getter->setBodyTypeCheckedIfPresent(); } bodyStmts.clear(); if (auto setter = VD->getSetter()) { Expr *selfExpr = makeSelfExpr(setter, ValueImpl->getSetter()); auto implRef = ConcreteDeclRef(ValueImpl, SelfContextSubs); auto implMemberExpr = new (Context) MemberRefExpr(selfExpr, SourceLoc(), implRef, DeclNameLoc(), /*implicit*/ true); auto valueLVTy = LValueType::get(valueTy); implMemberExpr->setType(valueLVTy); implMemberExpr->propagateLValueAccessKind(AccessKind::Write); ConcreteDeclRef newValueRef = getFirstParamDecl(setter); auto newValueExpr = new (Context) DeclRefExpr(newValueRef, DeclNameLoc(), /*implicit*/ true); newValueExpr->setType(valueTy); auto assign = new (Context) AssignExpr(implMemberExpr, SourceLoc(), newValueExpr, /*implicit*/ true); assign->setType(TupleType::getEmpty(Context)); bodyStmts.push_back(assign); auto body = BraceStmt::create(Context, SourceLoc(), bodyStmts, SourceLoc(), /*implicit*/ true); setter->setBody(body); setter->setBodyTypeCheckedIfPresent(); } } void TypeChecker::completeLazyVarImplementation(VarDecl *VD) { assert(VD->getAttrs().hasAttribute()); assert(VD->getStorageKind() == AbstractStorageDecl::Computed && "variable not validated yet"); 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 = VD->getName().str(); NameBuf += ".storage"; 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, StorageTy, 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 = new (Context) TypedPattern(PBDPattern, TypeLoc::withoutLoc(StorageTy), /*implicit*/true); auto *PBD = PatternBindingDecl::create(Context, /*staticloc*/SourceLoc(), StaticSpellingKind::None, /*varloc*/VD->getLoc(), PBDPattern, /*init*/nullptr, VD->getDeclContext()); PBD->setImplicit(); addMemberToContextIfNeeded(PBD, VD->getDeclContext(), VD); // Now that we've got the storage squared away, synthesize the getter. completeLazyPropertyGetter(VD, Storage, *this); // The setter just forwards on to storage without materializing the initial // value. auto *Set = VD->getSetter(); VarDecl *SetValueDecl = getFirstParamDecl(Set); // FIXME: This is wrong for observed properties. synthesizeTrivialSetter(Set, Storage, SetValueDecl, *this); // 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()->getAsClassOrClassExtensionContext()) makeFinal(Context, Storage); Storage->setImplicit(); Storage->setAccess(AccessLevel::Private); Storage->setSetterAccess(AccessLevel::Private); } /// Consider add a materializeForSet accessor to the given storage /// decl (which has accessors). void swift::maybeAddMaterializeForSet(AbstractStorageDecl *storage, TypeChecker &TC) { assert(storage->hasAccessorFunctions()); // Be idempotent. There are a bunch of places where we want to // ensure that there's a materializeForSet accessor. if (storage->getMaterializeForSetFunc()) return; // Never add materializeForSet to readonly declarations. if (!storage->getSetter()) return; // We only need materializeForSet in type contexts. auto *dc = storage->getDeclContext(); if (!dc->isTypeContext()) return; // Requirements of ObjC protocols don't need this. if (auto protoDecl = dyn_cast(dc)) if (protoDecl->isObjC()) return; // Members of structs imported by Clang don't need this, because we can // synthesize it later. if (auto structDecl = dyn_cast(dc)) if (structDecl->hasClangNode()) return; addMaterializeForSet(storage, TC); } void swift::maybeAddAccessorsToVariable(VarDecl *var, TypeChecker &TC) { if (var->getGetter()) return; auto *dc = var->getDeclContext(); assert(!var->hasAccessorFunctions()); // Introduce accessors for a property with behaviors. if (var->hasBehavior()) { assert(!var->getBehavior()->Conformance.hasValue()); // The property should be considered computed by the time we're through. SWIFT_DEFER { assert(!var->hasStorage() && "behavior var was not made computed"); }; auto behavior = var->getMutableBehavior(); NormalProtocolConformance *conformance = nullptr; VarDecl *valueProp = nullptr; bool mightBeMutating = dc->isTypeContext() && !var->isStatic() && !dc->getDeclaredInterfaceType()->hasReferenceSemantics(); auto makeBehaviorAccessors = [&]{ AccessorDecl *getter; AccessorDecl *setter = nullptr; if (valueProp && valueProp->getGetter()) { getter = createGetterPrototype(var, TC); // The getter is mutating if the behavior implementation is, unless // we're in a class or non-instance context. if (mightBeMutating && valueProp->isGetterMutating()) getter->setSelfAccessKind(SelfAccessKind::Mutating); getter->setAccess(var->getFormalAccess()); // Make a setter if the behavior property has one. if (valueProp->getSetter()) { ParamDecl *newValueParam = nullptr; setter = createSetterPrototype(var, newValueParam, TC); if (mightBeMutating && valueProp->isSetterMutating()) setter->setSelfAccessKind(SelfAccessKind::Mutating); // TODO: max of property and implementation setter visibility? setter->setAccess(var->getFormalAccess()); } } else { // Even if we couldn't find a value property, still make up a stub // getter and setter, so that subsequent diagnostics make sense for a // computed-ish property. getter = createGetterPrototype(var, TC); getter->setAccess(var->getFormalAccess()); ParamDecl *newValueParam = nullptr; setter = createSetterPrototype(var, newValueParam, TC); setter->setSelfAccessKind(SelfAccessKind::NonMutating); setter->setAccess(var->getFormalAccess()); } SmallVector accessors; accessors.push_back(getter); if (setter) accessors.push_back(setter); var->setAccessors(VarDecl::Computed, SourceLoc(), accessors, SourceLoc()); // Save the conformance and 'value' decl for later type checking. behavior->Conformance = conformance; behavior->ValueDecl = valueProp; addMemberToContextIfNeeded(getter, dc, var); if (setter) addMemberToContextIfNeeded(setter, dc, getter); }; // Try to resolve the behavior to a protocol. auto behaviorType = TC.resolveType(behavior->ProtocolName, dc, TypeResolutionOptions()); if (!behaviorType) { return makeBehaviorAccessors(); } { // The type must refer to a protocol. auto behaviorProtoTy = behaviorType->getAs(); if (!behaviorProtoTy) { TC.diagnose(behavior->getLoc(), diag::property_behavior_not_protocol); behavior->Conformance = (NormalProtocolConformance*)nullptr; return makeBehaviorAccessors(); } auto behaviorProto = behaviorProtoTy->getDecl(); // Validate the behavior protocol and all its extensions so we can do // name lookup. TC.validateDecl(behaviorProto); for (auto ext : behaviorProto->getExtensions()) { TC.validateExtension(ext); } // Look up the behavior protocol's "value" property, or bail if it doesn't // have one. The property's accessors will decide whether the getter // is mutating, and whether there's a setter. We'll type-check to make // sure the property type matches later after validation. auto lookup = TC.lookupMember(dc, behaviorProtoTy, TC.Context.Id_value); for (auto found : lookup) { if (auto foundVar = dyn_cast(found.getValueDecl())) { if (valueProp) { TC.diagnose(behavior->getLoc(), diag::property_behavior_protocol_reqt_ambiguous, TC.Context.Id_value); TC.diagnose(valueProp->getLoc(), diag::identifier_declared_here, TC.Context.Id_value); TC.diagnose(foundVar->getLoc(), diag::identifier_declared_here, TC.Context.Id_value); break; } valueProp = foundVar; } } if (!valueProp) { TC.diagnose(behavior->getLoc(), diag::property_behavior_protocol_no_value); return makeBehaviorAccessors(); } TC.validateDecl(valueProp); var->setIsGetterMutating(mightBeMutating && valueProp->isGetterMutating()); var->setIsSetterMutating(mightBeMutating && valueProp->isSetterMutating()); // Set up a conformance to represent the behavior instantiation. // The conformance will be on the containing 'self' type, or '()' if the // property is in a non-type context. Type behaviorSelf; if (dc->isTypeContext()) { behaviorSelf = dc->getSelfInterfaceType(); assert(behaviorSelf && "type context doesn't have self type?!"); if (var->isStatic()) behaviorSelf = MetatypeType::get(behaviorSelf); } else { behaviorSelf = TC.Context.TheEmptyTupleType; } conformance = TC.Context.getBehaviorConformance(behaviorSelf, behaviorProto, behavior->getLoc(), var, ProtocolConformanceState::Checking); } return makeBehaviorAccessors(); } // Lazy properties require special handling. if (var->getAttrs().hasAttribute()) { auto *getter = createGetterPrototype(var, TC); // lazy getters are mutating on an enclosing value type. if (!dc->getAsClassOrClassExtensionContext()) { getter->setSelfAccessKind(SelfAccessKind::Mutating); var->setIsGetterMutating(true); } getter->setAccess(var->getFormalAccess()); ParamDecl *newValueParam = nullptr; auto *setter = createSetterPrototype(var, newValueParam, TC); AccessorDecl *materializeForSet = nullptr; if (dc->getAsNominalTypeOrNominalTypeExtensionContext()) { materializeForSet = createMaterializeForSetPrototype(var, getter, setter, TC); } SmallVector accessors; accessors.push_back(getter); accessors.push_back(setter); if (materializeForSet) accessors.push_back(materializeForSet); var->setAccessors(VarDecl::Computed, SourceLoc(), accessors, SourceLoc()); addMemberToContextIfNeeded(getter, dc, var); addMemberToContextIfNeeded(setter, dc, getter); if (materializeForSet) addMemberToContextIfNeeded(materializeForSet, dc, setter); return; } // Local variables don't otherwise get accessors. if (dc->isLocalContext()) return; // Implicit properties don't get accessors. if (var->isImplicit()) return; if (!dc->isTypeContext()) { // Fixed-layout global variables don't get accessors. if (!var->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(dc)) { if (var->hasStorage()) { if (var->isLet()) TC.diagnose(var->getLoc(), diag::protocol_property_must_be_computed_var); else TC.diagnose(var->getLoc(), diag::protocol_property_must_be_computed); convertStoredVarInProtocolToComputed(var, TC); } return; // NSManaged properties on classes require special handling. } else if (dc->getAsClassOrClassExtensionContext()) { if (var->getAttrs().hasAttribute()) { convertNSManagedStoredVarToComputed(var, TC); return; } // Stored properties imported from Clang don't get accessors. } else if (auto *structDecl = dyn_cast(dc)) { if (structDecl->hasClangNode()) return; } // Stored properties in SIL mode don't get accessors. if (auto sourceFile = dc->getParentSourceFile()) if (sourceFile->Kind == SourceFileKind::SIL) return; // Everything else gets accessors. addTrivialAccessorsToStorage(var, TC); } /// \brief 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 &context = tc.Context; SourceLoc Loc = decl->getLoc(); auto accessLevel = AccessLevel::Internal; // Determine the parameter type of the implicit constructor. SmallVector params; if (ICK == ImplicitConstructorKind::Memberwise) { assert(isa(decl) && "Only struct have memberwise constructor"); for (auto member : decl->getMembers()) { auto var = dyn_cast(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; tc.validateDecl(var); if (!var->hasStorage() && !var->getAttrs().hasAttribute()) 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()); auto varType = var->getType() ->getReferenceStorageReferent(); auto varInterfaceType = var->getInterfaceType() ->getReferenceStorageReferent(); // 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()) { varType = OptionalType::get(varType); varInterfaceType = OptionalType::get(varInterfaceType); } // Create the parameter. auto *arg = new (context) ParamDecl(VarDecl::Specifier::Default, SourceLoc(), Loc, var->getName(), Loc, var->getName(), varType, decl); arg->setInterfaceType(varInterfaceType); arg->setImplicit(); params.push_back(arg); } } auto paramList = ParameterList::create(context, params); // Create the constructor. DeclName name(context, DeclBaseName::createConstructor(), paramList); auto *selfParam = ParamDecl::createSelf(Loc, decl, /*static*/false, /*inout*/true); auto *ctor = new (context) ConstructorDecl(name, Loc, OTK_None, /*FailabilityLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), selfParam, paramList, nullptr, decl); // Mark implicit. ctor->setImplicit(); ctor->setAccess(accessLevel); if (ICK == ImplicitConstructorKind::Memberwise) ctor->setIsMemberwiseInitializer(); // 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(decl)) { if (classDecl->getSuperclass()) ctor->getAttrs().add(new (tc.Context) OverrideAttr(/*IsImplicit=*/true)); } // Type-check the constructor declaration. tc.validateDecl(ctor); return ctor; } /// Create a stub body that emits a fatal error message. static void createStubBody(TypeChecker &tc, ConstructorDecl *ctor) { auto unimplementedInitDecl = tc.Context.getUnimplementedInitializerDecl(&tc); auto classDecl = ctor->getDeclContext()->getAsClassOrClassExtensionContext(); if (!unimplementedInitDecl) { tc.diagnose(classDecl->getLoc(), diag::missing_unimplemented_init_runtime); return; } // Create a call to Swift._unimplementedInitializer auto loc = classDecl->getLoc(); Expr *fn = new (tc.Context) DeclRefExpr(unimplementedInitDecl, DeclNameLoc(loc), /*Implicit=*/true); llvm::SmallString<64> buffer; StringRef fullClassName = tc.Context.AllocateCopy( (classDecl->getModuleContext()->getName().str() + "." + classDecl->getName().str()).toStringRef(buffer)); Expr *className = new (tc.Context) StringLiteralExpr(fullClassName, loc, /*Implicit=*/true); Expr *call = CallExpr::createImplicit(tc.Context, fn, { className }, { tc.Context.Id_className }); ctor->setBody(BraceStmt::create(tc.Context, SourceLoc(), ASTNode(call), SourceLoc(), /*implicit=*/true)); // Note that this is a stub implementation. ctor->setStubImplementation(true); } static std::tuple configureGenericDesignatedInitOverride(ASTContext &ctx, ClassDecl *classDecl, Type superclassTy, ConstructorDecl *superclassCtor) { auto *superclassDecl = superclassTy->getAnyNominal(); auto *moduleDecl = classDecl->getParentModule(); auto subMap = superclassTy->getContextSubstitutionMap( moduleDecl, superclassDecl); GenericSignature *genericSig; GenericEnvironment *genericEnv; // Inheriting initializers that have their own generic parameters auto *genericParams = superclassCtor->getGenericParams(); if (genericParams) { SmallVector 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); } // Substitution map that maps the generic parameters of the superclass // to the generic parameters of the derived class, and the generic // parameters of the superclass initializer to the generic parameters // of the derived class initializer. auto *superclassSig = superclassCtor->getGenericSignature(); if (superclassSig) { unsigned superclassDepth = 0; if (auto *genericSig = superclassDecl->getGenericSignature()) superclassDepth = genericSig->getGenericParams().back()->getDepth() + 1; subMap = SubstitutionMap::get( superclassSig, [&](SubstitutableType *type) -> Type { auto *gp = cast(type); if (gp->getDepth() < superclassDepth) return Type(gp).subst(subMap); return CanGenericTypeParamType::get( gp->getDepth() - superclassDepth + depth, gp->getIndex(), ctx); }, [&](CanType depTy, Type substTy, ProtocolDecl *proto) -> Optional { if (auto conf = subMap.lookupConformance(depTy, proto)) return conf; return ProtocolConformanceRef(proto); }); } // We don't have to clone the requirements, because they're not // used for anything. genericParams = GenericParamList::create(ctx, SourceLoc(), newParams, SourceLoc(), ArrayRef(), SourceLoc()); genericParams->setOuterParameters(classDecl->getGenericParamsOfContext()); GenericSignatureBuilder builder(ctx); builder.addGenericSignature(classDecl->getGenericSignature()); for (auto *newParam : newParams) builder.addGenericParameter(newParam); auto source = GenericSignatureBuilder::FloatingRequirementSource::forAbstract(); for (auto reqt : superclassSig->getRequirements()) if (auto substReqt = reqt.subst(subMap)) builder.addRequirement(*substReqt, source, nullptr); genericSig = std::move(builder).computeGenericSignature(SourceLoc()); genericEnv = genericSig->createGenericEnvironment(); } else { genericEnv = classDecl->getGenericEnvironment(); genericSig = classDecl->getGenericSignature(); } return std::make_tuple(genericSig, genericEnv, genericParams, subMap); } static void configureDesignatedInitAttributes(TypeChecker &tc, ClassDecl *classDecl, ConstructorDecl *ctor, ConstructorDecl *superclassCtor) { auto &ctx = tc.Context; AccessLevel access = classDecl->getFormalAccess(); access = std::max(access, AccessLevel::Internal); access = std::min(access, superclassCtor->getFormalAccess()); ctor->setAccess(access); // Inherit the @inlinable attribute. if (superclassCtor->getFormalAccess(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true) >= AccessLevel::Public) { if (superclassCtor->getAttrs().hasAttribute()) { auto *clonedAttr = new (ctx) InlinableAttr(/*implicit=*/true); ctor->getAttrs().add(clonedAttr); } } // Inherit the @usableFromInline attribute. We need better abstractions // for dealing with @usableFromInline. if (superclassCtor->getFormalAccess(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true) >= AccessLevel::Public) { if (access == AccessLevel::Internal && !superclassCtor->isDynamic() && !ctor->getAttrs().hasAttribute()) { auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true); ctor->getAttrs().add(clonedAttr); } } // Inherit the @discardableResult attribute. if (superclassCtor->getAttrs().hasAttribute()) { 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()) { AvailabilityInference::applyInferredAvailableAttrs( ctor, {classDecl, superclassCtor}, ctx); } if (superclassCtor->isObjC()) { // Inherit the @objc name from the superclass initializer, if it // has one. if (auto objcAttr = superclassCtor->getAttrs().getAttribute()) { if (objcAttr->hasName()) { auto *clonedAttr = objcAttr->clone(ctx); clonedAttr->setImplicit(true); ctor->getAttrs().add(clonedAttr); } } auto errorConvention = superclassCtor->getForeignErrorConvention(); markAsObjC(tc, ctor, ObjCReason::ImplicitlyObjC, errorConvention); } if (superclassCtor->isRequired()) ctor->getAttrs().add(new (ctx) RequiredAttr(/*IsImplicit=*/true)); if (superclassCtor->isDynamic()) ctor->getAttrs().add(new (ctx) DynamicAttr(/*IsImplicit*/true)); // Wire up the overrides. ctor->getAttrs().add(new (ctx) OverrideAttr(/*IsImplicit=*/true)); ctor->setOverriddenDecl(superclassCtor); } 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() ->getAsNominalTypeOrNominalTypeExtensionContext(); Type superclassTy = classDecl->getSuperclass(); NominalTypeDecl *superclassDecl = superclassTy->getAnyNominal(); if (superclassCtorDecl != superclassDecl) { return nullptr; } GenericSignature *genericSig; GenericEnvironment *genericEnv; GenericParamList *genericParams; SubstitutionMap subMap; std::tie(genericSig, genericEnv, genericParams, subMap) = configureGenericDesignatedInitOverride(ctx, classDecl, superclassTy, superclassCtor); // Determine the initializer parameters. // Create the 'self' declaration and patterns. auto *selfDecl = ParamDecl::createSelf(SourceLoc(), classDecl); // Create the initializer parameter patterns. OptionSet options = ParameterList::Implicit; options |= ParameterList::Inherited; auto *bodyParams = superclassCtor->getParameterList(1)->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'. for (auto *decl : *bodyParams) { auto paramTy = decl->getInterfaceType(); auto substTy = paramTy.subst(subMap); decl->setInterfaceType(substTy); decl->setType(GenericEnvironment::mapTypeIntoContext(genericEnv, 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(), selfDecl, bodyParams, genericParams, classDecl); ctor->setImplicit(); // Set the interface type of the initializer. ctor->setGenericEnvironment(genericEnv); tc.configureInterfaceType(ctor, genericSig); ctor->setValidationStarted(); configureDesignatedInitAttributes(tc, classDecl, ctor, superclassCtor); if (kind == DesignatedInitKind::Stub) { // Make this a stub implementation. createStubBody(tc, ctor); ctor->setNeedsNewVTableEntry(false); return ctor; } // Form the body of a chaining designated initializer. assert(kind == DesignatedInitKind::Chaining); // Reference to super.init. 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); // If buildArgumentForwardingExpr failed, then it was because we tried to // forward varargs, which cannot be done yet. // TODO: We should be able to forward varargs! if (!ctorArgs) { tc.diagnose(classDecl->getLoc(), diag::unsupported_synthesize_init_variadic, classDecl->getDeclaredType()); tc.diagnose(superclassCtor, diag::variadic_superclass_init_here); createStubBody(tc, ctor); return ctor; } 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(tc.Context, SourceLoc(), ASTNode(superCall), SourceLoc(), /*implicit=*/true)); return ctor; }