//===--- Decl.cpp - Swift Language Decl ASTs ------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 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 the Decl class and subclasses. // //===----------------------------------------------------------------------===// #include "swift/AST/Decl.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTMangler.h" #include "swift/AST/ASTPrinter.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/AccessRequests.h" #include "swift/AST/AccessScope.h" #include "swift/AST/Attr.h" #include "swift/AST/CaptureInfo.h" #include "swift/AST/ConformanceLookup.h" #include "swift/AST/DeclExportabilityVisitor.h" #include "swift/AST/DiagnosticEngine.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/Expr.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/GenericSignature.h" #include "swift/AST/ImportCache.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/MacroDefinition.h" #include "swift/AST/MacroDiscriminatorContext.h" #include "swift/AST/Module.h" #include "swift/AST/NameLookup.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ParseRequests.h" #include "swift/AST/Pattern.h" #include "swift/AST/PropertyWrappers.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/ResilienceExpansion.h" #include "swift/AST/SourceFile.h" #include "swift/AST/Stmt.h" #include "swift/AST/SwiftNameTranslation.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeLoc.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Defer.h" #include "swift/Basic/Range.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/StringExtras.h" #include "swift/Basic/TypeID.h" #include "swift/ClangImporter/ClangImporterRequests.h" #include "swift/ClangImporter/ClangModule.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Parse/Lexer.h" // FIXME: Bad dependency #include "clang/Lex/MacroInfo.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Module.h" #include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "InlinableText.h" #include using namespace swift; #define DEBUG_TYPE "Serialization" STATISTIC(NumLazyRequirementSignatures, "# of lazily-deserialized requirement signatures known"); #undef DEBUG_TYPE #define DECL(Id, _) \ static_assert((DeclKind::Id == DeclKind::Module) ^ \ IsTriviallyDestructible::value, \ "Decls are BumpPtrAllocated; the destructor is never called"); #include "swift/AST/DeclNodes.def" static_assert(IsTriviallyDestructible::value, "ParameterLists are BumpPtrAllocated; the d'tor is never called"); static_assert(IsTriviallyDestructible::value, "GenericParamLists are BumpPtrAllocated; the d'tor isn't called"); const clang::MacroInfo *ClangNode::getAsMacro() const { if (auto MM = getAsModuleMacro()) return MM->getMacroInfo(); return getAsMacroInfo(); } clang::SourceLocation ClangNode::getLocation() const { if (auto D = getAsDecl()) return D->getLocation(); if (auto M = getAsMacro()) return M->getDefinitionLoc(); return clang::SourceLocation(); } clang::SourceRange ClangNode::getSourceRange() const { if (auto D = getAsDecl()) return D->getSourceRange(); if (auto M = getAsMacro()) return clang::SourceRange(M->getDefinitionLoc(), M->getDefinitionEndLoc()); return clang::SourceLocation(); } const clang::Module *ClangNode::getClangModule() const { if (auto *M = getAsModule()) return M; if (auto *ID = dyn_cast_or_null(getAsDecl())) return ID->getImportedModule(); return nullptr; } void ClangNode::dump() const { if (auto D = getAsDecl()) D->dump(); else if (auto M = getAsMacro()) M->dump(); else if (auto M = getAsModule()) M->dump(); else llvm::errs() << "ClangNode contains nullptr\n"; } StringRef Decl::getKindName(DeclKind K) { switch (K) { #define DECL(Id, Parent) case DeclKind::Id: return #Id; #include "swift/AST/DeclNodes.def" } llvm_unreachable("bad DeclKind"); } DescriptiveDeclKind Decl::getDescriptiveKind() const { #define TRIVIAL_KIND(Kind) \ case DeclKind::Kind: \ return DescriptiveDeclKind::Kind switch (getKind()) { TRIVIAL_KIND(Import); TRIVIAL_KIND(Extension); TRIVIAL_KIND(EnumCase); TRIVIAL_KIND(TopLevelCode); TRIVIAL_KIND(PoundDiagnostic); TRIVIAL_KIND(PatternBinding); TRIVIAL_KIND(PrecedenceGroup); TRIVIAL_KIND(InfixOperator); TRIVIAL_KIND(PrefixOperator); TRIVIAL_KIND(PostfixOperator); TRIVIAL_KIND(TypeAlias); TRIVIAL_KIND(GenericTypeParam); TRIVIAL_KIND(AssociatedType); TRIVIAL_KIND(Protocol); TRIVIAL_KIND(Constructor); TRIVIAL_KIND(Destructor); TRIVIAL_KIND(EnumElement); TRIVIAL_KIND(Param); TRIVIAL_KIND(Module); TRIVIAL_KIND(Missing); TRIVIAL_KIND(MissingMember); TRIVIAL_KIND(Macro); TRIVIAL_KIND(MacroExpansion); case DeclKind::Enum: return cast(this)->getGenericParams() ? DescriptiveDeclKind::GenericEnum : DescriptiveDeclKind::Enum; case DeclKind::Struct: return cast(this)->getGenericParams() ? DescriptiveDeclKind::GenericStruct : DescriptiveDeclKind::Struct; case DeclKind::Class: { auto clazz = cast(this); bool isAnyActor = clazz->isAnyActor(); bool isGeneric = clazz->getGenericParams(); auto kind = isGeneric ? DescriptiveDeclKind::GenericClass : DescriptiveDeclKind::Class; if (isAnyActor) { if (clazz->isDistributedActor()) { kind = isGeneric ? DescriptiveDeclKind::GenericDistributedActor : DescriptiveDeclKind::DistributedActor; } else { kind = isGeneric ? DescriptiveDeclKind::GenericActor : DescriptiveDeclKind::Actor; } } return kind; } case DeclKind::Var: { auto var = cast(this); switch (var->getCorrectStaticSpelling()) { case StaticSpellingKind::None: if (var->getDeclContext()->isTypeContext()) { if (var->isDistributed() && !var->isLet()) { return DescriptiveDeclKind::DistributedProperty; } return DescriptiveDeclKind::Property; } return var->isLet() ? DescriptiveDeclKind::Let : DescriptiveDeclKind::Var; case StaticSpellingKind::KeywordStatic: return DescriptiveDeclKind::StaticProperty; case StaticSpellingKind::KeywordClass: return DescriptiveDeclKind::ClassProperty; } } case DeclKind::Subscript: { auto subscript = cast(this); switch (subscript->getCorrectStaticSpelling()) { case StaticSpellingKind::None: return DescriptiveDeclKind::Subscript; case StaticSpellingKind::KeywordStatic: return DescriptiveDeclKind::StaticSubscript; case StaticSpellingKind::KeywordClass: return DescriptiveDeclKind::ClassSubscript; } } case DeclKind::Accessor: { auto accessor = cast(this); switch (accessor->getAccessorKind()) { case AccessorKind::Get: case AccessorKind::DistributedGet: return DescriptiveDeclKind::Getter; case AccessorKind::Set: return DescriptiveDeclKind::Setter; case AccessorKind::WillSet: return DescriptiveDeclKind::WillSet; case AccessorKind::DidSet: return DescriptiveDeclKind::DidSet; case AccessorKind::Address: return DescriptiveDeclKind::Addressor; case AccessorKind::MutableAddress: return DescriptiveDeclKind::MutableAddressor; case AccessorKind::Read: case AccessorKind::Read2: return DescriptiveDeclKind::ReadAccessor; case AccessorKind::Modify: case AccessorKind::Modify2: return DescriptiveDeclKind::ModifyAccessor; case AccessorKind::Init: return DescriptiveDeclKind::InitAccessor; } llvm_unreachable("bad accessor kind"); } case DeclKind::Func: { auto func = cast(this); if (func->isOperator()) return DescriptiveDeclKind::OperatorFunction; if (func->getDeclContext()->isLocalContext()) return DescriptiveDeclKind::LocalFunction; if (func->getDeclContext()->isModuleScopeContext()) return DescriptiveDeclKind::GlobalFunction; // We have a method. switch (func->getCorrectStaticSpelling()) { case StaticSpellingKind::None: if (func->isDistributed()) { return DescriptiveDeclKind::DistributedMethod; } else { return DescriptiveDeclKind::Method; } case StaticSpellingKind::KeywordStatic: return DescriptiveDeclKind::StaticMethod; case StaticSpellingKind::KeywordClass: return DescriptiveDeclKind::ClassMethod; } } case DeclKind::OpaqueType: { auto *opaqueTypeDecl = cast(this); if (dyn_cast_or_null(opaqueTypeDecl->getNamingDecl())) return DescriptiveDeclKind::OpaqueVarType; return DescriptiveDeclKind::OpaqueResultType; } case DeclKind::BuiltinTuple: llvm_unreachable("BuiltinTupleDecl should not end up here"); } #undef TRIVIAL_KIND llvm_unreachable("bad DescriptiveDeclKind"); } StringRef Decl::getDescriptiveKindName(DescriptiveDeclKind K) { #define ENTRY(Kind, String) case DescriptiveDeclKind::Kind: return String switch (K) { ENTRY(Import, "import"); ENTRY(Extension, "extension"); ENTRY(EnumCase, "case"); ENTRY(TopLevelCode, "top-level code"); ENTRY(PoundDiagnostic, "diagnostic"); ENTRY(PatternBinding, "pattern binding"); ENTRY(Var, "var"); ENTRY(Param, "parameter"); ENTRY(Let, "let"); ENTRY(Property, "property"); ENTRY(StaticProperty, "static property"); ENTRY(ClassProperty, "class property"); ENTRY(DistributedProperty, "distributed property"); ENTRY(PrecedenceGroup, "precedence group"); ENTRY(InfixOperator, "infix operator"); ENTRY(PrefixOperator, "prefix operator"); ENTRY(PostfixOperator, "postfix operator"); ENTRY(TypeAlias, "type alias"); ENTRY(GenericTypeParam, "generic parameter"); ENTRY(AssociatedType, "associated type"); ENTRY(Type, "type"); ENTRY(Enum, "enum"); ENTRY(Struct, "struct"); ENTRY(Class, "class"); ENTRY(Actor, "actor"); ENTRY(DistributedActor, "distributed actor"); ENTRY(Protocol, "protocol"); ENTRY(GenericEnum, "generic enum"); ENTRY(GenericStruct, "generic struct"); ENTRY(GenericClass, "generic class"); ENTRY(GenericActor, "generic actor"); ENTRY(GenericDistributedActor, "generic distributed actor"); ENTRY(GenericType, "generic type"); ENTRY(Subscript, "subscript"); ENTRY(StaticSubscript, "static subscript"); ENTRY(ClassSubscript, "class subscript"); ENTRY(Constructor, "initializer"); ENTRY(Destructor, "deinitializer"); ENTRY(LocalFunction, "local function"); ENTRY(GlobalFunction, "global function"); ENTRY(OperatorFunction, "operator function"); ENTRY(Method, "instance method"); ENTRY(StaticMethod, "static method"); ENTRY(ClassMethod, "class method"); ENTRY(DistributedMethod, "distributed instance method"); ENTRY(Getter, "getter"); ENTRY(Setter, "setter"); ENTRY(WillSet, "willSet observer"); ENTRY(DidSet, "didSet observer"); ENTRY(Addressor, "address accessor"); ENTRY(MutableAddressor, "mutableAddress accessor"); ENTRY(ReadAccessor, "_read accessor"); ENTRY(ModifyAccessor, "_modify accessor"); ENTRY(InitAccessor, "init acecssor"); ENTRY(EnumElement, "enum case"); ENTRY(Module, "module"); ENTRY(Missing, "missing decl"); ENTRY(MissingMember, "missing member placeholder"); ENTRY(Requirement, "requirement"); ENTRY(OpaqueResultType, "result"); ENTRY(OpaqueVarType, "type"); ENTRY(Macro, "macro"); ENTRY(MacroExpansion, "pound literal"); } #undef ENTRY llvm_unreachable("bad DescriptiveDeclKind"); } ParsedDeclAttributes Decl::getParsedAttrs() const { return ParsedDeclAttributes(getAttrs(), this); } DeclAttributes Decl::getExpandedAttrs() const { auto mutableThis = const_cast(this); (void)evaluateOrDefault(getASTContext().evaluator, ExpandMemberAttributeMacros{mutableThis}, {}); return getAttrs(); } DeclAttributes Decl::getSemanticAttrs() const { (void)evaluateOrDefault(getASTContext().evaluator, SemanticDeclAttrsRequest{this}, {}); return getAttrs(); } void Decl::visitAuxiliaryDecls( AuxiliaryDeclCallback callback, bool visitFreestandingExpanded ) const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); SourceManager &sourceMgr = ctx.SourceMgr; auto *moduleDecl = getModuleContext(); auto peerBuffers = evaluateOrDefault(ctx.evaluator, ExpandPeerMacroRequest{mutableThis}, {}); for (auto bufferID : peerBuffers) { auto startLoc = sourceMgr.getLocForBufferStart(bufferID); auto *sourceFile = moduleDecl->getSourceFileContainingLocation(startLoc); for (auto *peer : sourceFile->getTopLevelDecls()) { callback(peer); } } if (visitFreestandingExpanded) { Decl *thisDecl = mutableThis; // If this is a top-level code decl consisting of a macro expansion // expression that substituted with a macro expansion declaration, use // that instead. if (auto *tlcd = dyn_cast(thisDecl)) { if (auto body = tlcd->getBody()) { if (body->getNumElements() == 1) { if (auto expr = body->getFirstElement().dyn_cast()) { if (auto expansion = dyn_cast(expr)) { if (auto substitute = expansion->getSubstituteDecl()) thisDecl = substitute; } } } } } if (auto *med = dyn_cast(thisDecl)) { if (auto bufferID = evaluateOrDefault( ctx.evaluator, ExpandMacroExpansionDeclRequest{med}, {})) { auto startLoc = sourceMgr.getLocForBufferStart(*bufferID); auto *sourceFile = moduleDecl->getSourceFileContainingLocation(startLoc); for (auto *decl : sourceFile->getTopLevelDecls()) callback(decl); } } } // FIXME: fold VarDecl::visitAuxiliaryDecls into this. } void Decl::forEachAttachedMacro(MacroRole role, MacroCallback macroCallback) const { for (auto customAttrConst : getExpandedAttrs().getAttributes()) { auto customAttr = const_cast(customAttrConst); auto *macroDecl = getResolvedMacro(customAttr); if (!macroDecl) continue; if (!macroDecl->getMacroRoles().contains(role)) continue; macroCallback(customAttr, macroDecl); } } MacroDecl *Decl::getResolvedMacro(CustomAttr *customAttr) const { auto declRef = evaluateOrDefault( getASTContext().evaluator, ResolveMacroRequest{customAttr, getDeclContext()}, ConcreteDeclRef()); return dyn_cast_or_null(declRef.getDecl()); } unsigned Decl::getAttachedMacroDiscriminator(DeclBaseName macroName, MacroRole role, const CustomAttr *attr) const { assert(isAttachedMacro(role) && "Not an attached macro role"); if (role != MacroRole::MemberAttribute) { llvm::SmallDenseMap nextDiscriminator; std::optional foundDiscriminator; forEachAttachedMacro( role, [&](CustomAttr *foundAttr, MacroDecl *foundMacro) { unsigned discriminator = nextDiscriminator[foundMacro->getBaseIdentifier()]++; if (attr == foundAttr) foundDiscriminator = discriminator; }); if (foundDiscriminator) return *foundDiscriminator; } // If that failed, conjure up a discriminator. // FIXME: Better discriminator for member attributes - add the member name? ASTContext &ctx = getASTContext(); assert(role == MacroRole::MemberAttribute || ctx.Diags.hadAnyError()); return ctx.getNextMacroDiscriminator( MacroDiscriminatorContext::getParentOf(getLoc(), getDeclContext()), macroName); } Type Decl::getResolvedCustomAttrType(CustomAttr *attr) const { if (auto ty = attr->getType()) return ty; auto dc = getDeclContext(); auto *nominal = evaluateOrDefault( getASTContext().evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); if (!nominal) return Type(); CustomAttrTypeKind kind; if (nominal->isGlobalActor()) { kind = CustomAttrTypeKind::GlobalActor; } else if (nominal->getAttrs().hasAttribute()) { kind = CustomAttrTypeKind::PropertyWrapper; } else { kind = CustomAttrTypeKind::NonGeneric; } return evaluateOrDefault(getASTContext().evaluator, CustomAttrTypeRequest{attr, dc, kind}, Type()); } bool Decl::isExposedToClients() const { return DeclExportabilityVisitor().visit(this); } const Decl *Decl::getInnermostDeclWithAvailability() const { if (getAttrs().hasAttribute()) return this; if (auto parent = AvailabilityInference::parentDeclForInferredAvailability(this)) return parent->getInnermostDeclWithAvailability(); return nullptr; } std::optional Decl::getIntroducedOSVersion(PlatformKind Kind) const { for (auto *attr: getAttrs()) { if (auto *ava = dyn_cast(attr)) { if (ava->Platform == Kind && ava->Introduced) { return ava->Introduced; } } } return std::nullopt; } std::optional Decl::getBackDeployedBeforeOSVersion(ASTContext &Ctx, bool forTargetVariant) const { if (auto *attr = getAttrs().getBackDeployed(Ctx, forTargetVariant)) { auto version = attr->Version; StringRef ignoredPlatformString; AvailabilityInference::updateBeforePlatformForFallback( attr, getASTContext(), ignoredPlatformString, version); // If the remap for fallback resulted in 1.0, then the // backdeployment prior to that is not meaningful. if (version == clang::VersionTuple(1, 0, 0, 0)) return std::nullopt; return version; } // Accessors may inherit `@backDeployed`. if (auto *AD = dyn_cast(this)) return AD->getStorage()->getBackDeployedBeforeOSVersion(Ctx, forTargetVariant); return std::nullopt; } bool Decl::isBackDeployed(ASTContext &Ctx) const { if (getBackDeployedBeforeOSVersion(Ctx)) return true; if (Ctx.LangOpts.TargetVariant) { if (getBackDeployedBeforeOSVersion(Ctx, /*forTargetVariant=*/true)) return true; } return false; } bool Decl::hasBackDeployedAttr() const { if (getAttrs().hasAttribute()) return true; // Accessors may inherit `@backDeployed`. if (auto *AD = dyn_cast(this)) return AD->getStorage()->hasBackDeployedAttr(); return false; } llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, StaticSpellingKind SSK) { switch (SSK) { case StaticSpellingKind::None: return OS << ""; case StaticSpellingKind::KeywordStatic: return OS << "'static'"; case StaticSpellingKind::KeywordClass: return OS << "'class'"; } llvm_unreachable("bad StaticSpellingKind"); } llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, ReferenceOwnership RO) { if (RO == ReferenceOwnership::Strong) return OS << "'strong'"; return OS << "'" << keywordOf(RO) << "'"; } llvm::raw_ostream &swift::operator<<(llvm::raw_ostream &OS, SelfAccessKind SAK) { switch (SAK) { case SelfAccessKind::NonMutating: return OS << "'nonmutating'"; case SelfAccessKind::Mutating: return OS << "'mutating'"; case SelfAccessKind::LegacyConsuming: return OS << "'__consuming'"; case SelfAccessKind::Consuming: return OS << "'consuming'"; case SelfAccessKind::Borrowing: return OS << "'borrowing'"; } llvm_unreachable("Unknown SelfAccessKind"); } DeclContext *Decl::getInnermostDeclContext() const { if (auto func = dyn_cast(this)) return const_cast(func); if (auto subscript = dyn_cast(this)) return const_cast(subscript); if (auto type = dyn_cast(this)) return const_cast(type); if (auto ext = dyn_cast(this)) return const_cast(ext); if (auto topLevel = dyn_cast(this)) return const_cast(topLevel); if (auto macro = dyn_cast(this)) return const_cast(macro); return getDeclContext(); } bool Decl::isInvalid() const { switch (getKind()) { #define VALUE_DECL(ID, PARENT) #define DECL(ID, PARENT) \ case DeclKind::ID: #include "swift/AST/DeclNodes.def" return Bits.Decl.Invalid; case DeclKind::Param: { // Parameters are special because closure parameters may not have type // annotations. In which case, the interface type request returns // ErrorType. Therefore, consider parameters with implicit types to always // be valid. auto *PD = cast(this); if (!PD->getTypeRepr() && !PD->hasInterfaceType()) return false; } LLVM_FALLTHROUGH; case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Protocol: case DeclKind::OpaqueType: case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::Module: case DeclKind::Var: case DeclKind::Subscript: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::Func: case DeclKind::EnumElement: case DeclKind::Macro: return cast(this)->getInterfaceType()->hasError(); case DeclKind::Accessor: { auto *AD = cast(this); if (AD->hasInterfaceType() && AD->getInterfaceType()->hasError()) return true; return AD->getStorage()->isInvalid(); } case DeclKind::BuiltinTuple: return false; } llvm_unreachable("Unknown decl kind"); } void Decl::setInvalidBit() { Bits.Decl.Invalid = true; } void Decl::setInvalid() { switch (getKind()) { #define VALUE_DECL(ID, PARENT) #define DECL(ID, PARENT) \ case DeclKind::ID: #include "swift/AST/DeclNodes.def" Bits.Decl.Invalid = true; return; case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Protocol: case DeclKind::OpaqueType: case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::Module: case DeclKind::Var: case DeclKind::Param: case DeclKind::Subscript: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::Func: case DeclKind::Accessor: case DeclKind::EnumElement: case DeclKind::Macro: cast(this)->setInterfaceType(ErrorType::get(getASTContext())); return; case DeclKind::BuiltinTuple: llvm_unreachable("BuiltinTupleDecl should not end up here"); } llvm_unreachable("Unknown decl kind"); } void Decl::setDeclContext(DeclContext *DC) { Context = DC; } bool Decl::isUserAccessible() const { if (auto VD = dyn_cast(this)) { return VD->isUserAccessible(); } return true; } bool Decl::canHaveComment() const { return !this->hasClangNode() && (isa(this) || isa(this)) && !isa(this) && !isa(this); } ModuleDecl *Decl::getModuleContext() const { return getDeclContext()->getParentModule(); } /// If `decl` is an imported Cxx decl, returns the actual module that the decl /// was imported from. This is necessary to compensate for the way that /// Cxx `namespace` declarations are imported. Since namespaces can span /// multiple Clang modules, the corresponding decls and all of their members get /// associated with the Clang imported header module (named `__ObjC`). This /// utility reaches through the Clang AST to find the actual module that members /// of namespaces originated from. static ModuleDecl *getModuleContextForNameLookupForCxxDecl(const Decl *decl) { auto &ctx = decl->getASTContext(); if (!ctx.LangOpts.EnableCXXInterop) return nullptr; if (!decl->hasClangNode()) return nullptr; auto parentModule = decl->getModuleContext(); // We only need to look for the real parent module when the existing parent // is the imported header module. if (!parentModule->isClangHeaderImportModule()) return nullptr; auto clangModule = decl->getClangDecl()->getOwningModule(); if (!clangModule) return nullptr; return ctx.getClangModuleLoader()->getWrapperForModule(clangModule); } ModuleDecl *Decl::getModuleContextForNameLookup() const { if (auto parentModule = getModuleContextForNameLookupForCxxDecl(this)) return parentModule; return getModuleContext(); } /// Retrieve the diagnostic engine for diagnostics emission. DiagnosticEngine &Decl::getDiags() const { return getASTContext().Diags; } // Helper functions to verify statically whether source-location // functions have been overridden. typedef const char (&TwoChars)[2]; template inline char checkSourceLocType(SourceLoc (Class::*)() const); inline TwoChars checkSourceLocType(SourceLoc (Decl::*)() const); template inline char checkSourceLocType(SourceLoc (Class::*)(bool) const); inline TwoChars checkSourceLocType(SourceLoc (Decl::*)(bool) const); template inline char checkSourceRangeType(SourceRange (Class::*)() const); inline TwoChars checkSourceRangeType(SourceRange (Decl::*)() const); SourceRange Decl::getSourceRange() const { switch (getKind()) { #define DECL(ID, PARENT) \ static_assert(sizeof(checkSourceRangeType(&ID##Decl::getSourceRange)) == 1, \ #ID "Decl is missing getSourceRange()"); \ case DeclKind::ID: return cast(this)->getSourceRange(); #include "swift/AST/DeclNodes.def" } llvm_unreachable("Unknown decl kind"); } SourceRange Decl::getSourceRangeIncludingAttrs() const { auto Range = getSourceRange(); // Attributes on AccessorDecl may syntactically belong to PatternBindingDecl. // e.g. 'override'. if (auto *AD = dyn_cast(this)) { // If this is implicit getter, accessor range should not include attributes. if (AD->isImplicitGetter()) return Range; // Otherwise, include attributes directly attached to the accessor. SourceLoc VarLoc = AD->getStorage()->getStartLoc(); for (auto *Attr : getParsedAttrs()) { if (!Attr->getRange().isValid()) continue; SourceLoc AttrStartLoc = Attr->getRangeWithAt().Start; if (getASTContext().SourceMgr.isBeforeInBuffer(VarLoc, AttrStartLoc)) Range.widen(AttrStartLoc); } return Range; } // Attributes on VarDecl syntactically belong to PatternBindingDecl. if (isa(this) && !isa(this)) return Range; // Attributes on PatternBindingDecls are attached to VarDecls in AST. if (auto *PBD = dyn_cast(this)) { for (auto i : range(PBD->getNumPatternEntries())) PBD->getPattern(i)->forEachVariable([&](VarDecl *VD) { for (auto *Attr : VD->getParsedAttrs()) if (Attr->getRange().isValid()) Range.widen(Attr->getRangeWithAt()); }); } for (auto *Attr : getParsedAttrs()) { if (Attr->getRange().isValid()) Range.widen(Attr->getRangeWithAt()); } return Range; } bool Decl::isInMacroExpansionInContext() const { auto *dc = getDeclContext(); auto parentFile = dc->getParentSourceFile(); auto *mod = getModuleContext(); auto *file = mod->getSourceFileContainingLocation(getStartLoc()); // Decls in macro expansions always have a source file. The source // file can be null if the decl is implicit or has an invalid // source location. if (!parentFile || !file) return false; if (file->getBufferID() == parentFile->getBufferID()) return false; return file->getFulfilledMacroRole() != std::nullopt; } SourceLoc Decl::getLocFromSource() const { switch (getKind()) { #define DECL(ID, X) \ static_assert(sizeof(checkSourceLocType(&ID##Decl::getLocFromSource)) == 1, \ #ID "Decl is missing getLocFromSource()"); \ case DeclKind::ID: return cast(this)->getLocFromSource(); #include "swift/AST/DeclNodes.def" } llvm_unreachable("Unknown decl kind"); } const ExternalSourceLocs *Decl::getSerializedLocs() const { auto &Context = getASTContext(); if (auto EL = Context.getExternalSourceLocs(this).value_or(nullptr)) return EL; static ExternalSourceLocs NullLocs{}; auto *File = cast(getDeclContext()->getModuleScopeContext()); if (File->getKind() != FileUnitKind::SerializedAST) return &NullLocs; auto RawLocs = File->getExternalRawLocsForDecl(this); if (!RawLocs.has_value()) { // Don't read .swiftsourceinfo again on failure Context.setExternalSourceLocs(this, &NullLocs); return &NullLocs; } auto &SM = getASTContext().SourceMgr; unsigned BufferID = SM.getExternalSourceBufferID(RawLocs->SourceFilePath); if (!BufferID) { // Don't try open the file again on failure Context.setExternalSourceLocs(this, &NullLocs); return &NullLocs; } CharSourceRange BufferRange = SM.getRangeForBuffer(BufferID); auto ResolveLoc = [&](const ExternalSourceLocs::RawLoc &Raw) -> SourceLoc { // If the underlying source has been updated and the swiftsourceinfo hasn't, // make sure we don't produce invalid source locations. Ideally would check // the file hasn't been modified. if (Raw.Offset > BufferRange.getByteLength()) return SourceLoc(); // If the decl had a presumed loc, create its virtual file so that // getPresumedLineAndColForLoc works from serialized locations as well. No // need to check the buffer range, the directive must be before the location // itself. if (Raw.Directive.isValid()) { auto &LD = Raw.Directive; SourceLoc Loc = SM.getLocForOffset(BufferID, LD.Offset); SM.createVirtualFile(Loc, LD.Name, LD.LineOffset, LD.Length); } return SM.getLocForOffset(BufferID, Raw.Offset); }; auto *Result = getASTContext().Allocate(); Result->BufferID = BufferID; Result->Loc = ResolveLoc(RawLocs->Loc); auto DocRanges = getASTContext().AllocateUninitialized(RawLocs->DocRanges.size()); for (auto I : indices(RawLocs->DocRanges)) { auto &Range = RawLocs->DocRanges[I]; DocRanges[I] = CharSourceRange(ResolveLoc(Range.first), Range.second); } Result->DocRanges = DocRanges; Context.setExternalSourceLocs(this, Result); return Result; } StringRef Decl::getAlternateModuleName() const { for (auto *Att: Attrs) { if (auto *OD = dyn_cast(Att)) { if (OD->isActivePlatform(getASTContext())) { return OD->OriginalModuleName; } } } for (auto *DC = getDeclContext(); DC; DC = DC->getParent()) { if (auto decl = DC->getAsDecl()) { if (decl == this) continue; auto AM = decl->getAlternateModuleName(); if (!AM.empty()) return AM; } } return StringRef(); } SourceLoc Decl::getLoc(bool SerializedOK) const { #define DECL(ID, X) \ static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 2, \ #ID "Decl is re-defining getLoc()"); #include "swift/AST/DeclNodes.def" if (isa(this)) return SourceLoc(); // When the decl is context-free, we should get loc from source buffer. if (!getDeclContext()) return getLocFromSource(); FileUnit *File = dyn_cast(getDeclContext()->getModuleScopeContext()); if (!File) return getLocFromSource(); switch(File->getKind()) { case FileUnitKind::Source: case FileUnitKind::ClangModule: return getLocFromSource(); case FileUnitKind::SerializedAST: { if (!SerializedOK) return SourceLoc(); return getSerializedLocs()->Loc; } case FileUnitKind::Builtin: case FileUnitKind::Synthesized: case FileUnitKind::DWARFModule: return SourceLoc(); } llvm_unreachable("invalid file kind"); } std::optional Decl::getGlobalActorAttr() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, GlobalActorAttributeRequest{mutableThis}, std::nullopt); } bool Decl::hasExplicitIsolationAttribute() const { if (auto nonisolatedAttr = getAttrs().getAttribute()) { if (!nonisolatedAttr->isImplicit()) return true; } if (auto isolatedAttr = getAttrs().getAttribute()) { if (!isolatedAttr->isImplicit()) { return true; } } if (auto globalActorAttr = getGlobalActorAttr()) { if (!globalActorAttr->first->isImplicit()) return true; } return false; } bool Decl::preconcurrency() const { if (getAttrs().hasAttribute()) return true; // Imported C declarations always predate concurrency. if (isa(getDeclContext()->getModuleScopeContext())) return true; // Variables declared in top-level code are @_predatesConcurrency if (const VarDecl *var = dyn_cast(this)) { const LangOptions &langOpts = getASTContext().LangOpts; return !langOpts.isSwiftVersionAtLeast(6) && var->isTopLevelGlobal() && var->getDeclContext()->isAsyncContext(); } return false; } bool Decl::isUnsafe() const { return evaluateOrDefault( getASTContext().evaluator, IsUnsafeRequest{const_cast(this)}, false); } Type AbstractFunctionDecl::getThrownInterfaceType() const { if (!getThrownTypeRepr()) return ThrownType.getType(); auto mutableThis = const_cast(this); return CatchNode(mutableThis).getExplicitCaughtType(getASTContext()); } std::optional AbstractFunctionDecl::getEffectiveThrownErrorType() const { // FIXME: Only getters can have thrown error types right now, and DidSet // has a cyclic reference if we try to get its interface type here. Find a // better way to express this. if (auto accessor = dyn_cast(this)) { if (accessor->getAccessorKind() != AccessorKind::Get && accessor->getAccessorKind() != AccessorKind::DistributedGet) { return std::nullopt; } } Type interfaceType = getInterfaceType(); if (hasImplicitSelfDecl()) { if (auto fnType = interfaceType->getAs()) interfaceType = fnType->getResult(); } if (auto fnType = interfaceType->getAs()) return fnType->getEffectiveThrownErrorType(); return std::nullopt; } bool AbstractStorageDecl::isCompileTimeConst() const { return getAttrs().hasAttribute(); } bool AbstractStorageDecl::isTransparent() const { return getAttrs().hasAttribute(); } bool AbstractFunctionDecl::isTransparent() const { // Check if the declaration had the attribute. if (getAttrs().hasAttribute()) return true; // If this is an accessor, the computation is a bit more involved, so we // kick off a request. if (const auto *AD = dyn_cast(this)) { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsAccessorTransparentRequest{const_cast(AD)}, false); } return false; } bool ParameterList::hasInternalParameter(StringRef Prefix) const { for (auto param : *this) { if (param->hasName() && param->getNameStr().starts_with(Prefix)) return true; auto argName = param->getArgumentName(); if (!argName.empty() && argName.str().starts_with(Prefix)) return true; } return false; } bool Decl::hasUnderscoredNaming() const { const Decl *D = this; // If it's a function or subscript with a parameter with leading // underscore, it's a private function or subscript. if (isa(D) || isa(D)) { const auto VD = cast(D); if (getParameterList(const_cast(VD)) ->hasInternalParameter("_")) { return true; } } if (const auto PD = dyn_cast(D)) { StringRef NameStr = PD->getNameStr(); if (NameStr.starts_with("_Builtin")) { return true; } if (NameStr.starts_with("_ExpressibleBy")) { return true; } } if (const auto ImportD = dyn_cast(D)) { if (const auto *Mod = ImportD->getModule()) { if (Mod->isSwiftShimsModule()) { return true; } } } const auto VD = dyn_cast(D); if (!VD || !VD->hasName()) { return false; } if (!VD->getBaseName().isSpecial() && VD->getBaseIdentifier().hasUnderscoredNaming()) { return true; } return false; } bool Decl::isPrivateSystemDecl(bool treatNonBuiltinProtocolsAsPublic) const { const Decl *D = this; if (auto ExtD = dyn_cast(D)) { Type extTy = ExtD->getExtendedType(); return extTy.isPrivateSystemType(treatNonBuiltinProtocolsAsPublic); } DeclContext *DC = D->getDeclContext()->getModuleScopeContext(); auto *M = DC->getParentModule(); if (M->isBuiltinModule() || M->isSwiftShimsModule()) return true; if (!M->isSystemModule() && !M->isNonUserModule()) return false; auto FU = dyn_cast(DC); if (!FU) return false; // Check for stdlib and imported Swift modules. if (!M->isStdlibModule() && FU->getKind() != FileUnitKind::SerializedAST) return false; if (isa(D)) { if (treatNonBuiltinProtocolsAsPublic) return false; } if (D->getAttrs().hasAttribute()) { return false; } return hasUnderscoredNaming(); } bool Decl::isStdlibDecl() const { DeclContext *DC = getDeclContext(); return DC->isModuleScopeContext() && DC->getParentModule()->isStdlibModule(); } LifetimeAnnotation Decl::getLifetimeAnnotationFromAttributes() const { auto &attrs = getAttrs(); if (attrs.hasAttribute()) return LifetimeAnnotation::EagerMove; if (attrs.hasAttribute()) return LifetimeAnnotation::Lexical; return LifetimeAnnotation::None; } LifetimeAnnotation Decl::getLifetimeAnnotation() const { if (auto *pd = dyn_cast(this)) { return pd->getLifetimeAnnotation(); } if (auto *fd = dyn_cast(this)) { return fd->getLifetimeAnnotation(); } return getLifetimeAnnotationFromAttributes(); } AvailabilityRange Decl::getAvailabilityForLinkage() const { ASTContext &ctx = getASTContext(); // When computing availability for linkage, use the "before" version from // the @backDeployed attribute, if present. if (auto backDeployVersion = getBackDeployedBeforeOSVersion(ctx)) return AvailabilityRange{VersionRange::allGTE(*backDeployVersion)}; auto containingContext = AvailabilityInference::annotatedAvailableRange(this); if (containingContext.has_value()) { // If this entity comes from the concurrency module, adjust its // availability for linkage purposes up to Swift 5.5, so that we use // weak references any time we reference those symbols when back-deploying // concurrency. if (getModuleContext()->getName() == ctx.Id_Concurrency) { containingContext->intersectWith(ctx.getConcurrencyAvailability()); } return *containingContext; } // FIXME: Adopt AvailabilityInference::parentDeclForInferredAvailability() // here instead of duplicating the logic. if (auto *accessor = dyn_cast(this)) return accessor->getStorage()->getAvailabilityForLinkage(); if (auto *opaqueTypeDecl = dyn_cast(this)) return opaqueTypeDecl->getNamingDecl()->getAvailabilityForLinkage(); if (auto *ext = dyn_cast(this)) if (auto *nominal = ext->getExtendedNominal()) return nominal->getAvailabilityForLinkage(); auto *dc = getDeclContext(); if (auto *ext = dyn_cast(dc)) return ext->getAvailabilityForLinkage(); else if (auto *nominal = dyn_cast(dc)) return nominal->getAvailabilityForLinkage(); return AvailabilityRange::alwaysAvailable(); } bool Decl::isAlwaysWeakImported() const { // For a Clang declaration, trust Clang. if (auto clangDecl = getClangDecl()) { return clangDecl->isWeakImported(); } if (getAttrs().hasAttribute()) return true; // FIXME: Weak linking on Windows is not yet supported // https://github.com/apple/swift/issues/53303 if (getSemanticUnavailableAttr() && !getASTContext().LangOpts.Target.isOSWindows()) return true; if (auto *accessor = dyn_cast(this)) return accessor->getStorage()->isAlwaysWeakImported(); if (auto *opaqueTypeDecl = dyn_cast(this)) return opaqueTypeDecl->getNamingDecl()->isAlwaysWeakImported(); if (auto *ext = dyn_cast(this)) if (auto *nominal = ext->getExtendedNominal()) return nominal->isAlwaysWeakImported(); auto *dc = getDeclContext(); if (auto *ext = dyn_cast(dc)) return ext->isAlwaysWeakImported(); if (auto *nominal = dyn_cast(dc)) return nominal->isAlwaysWeakImported(); return false; } bool Decl::isWeakImported(ModuleDecl *fromModule) const { if (fromModule == nullptr) { return (isAlwaysWeakImported() || !getAvailabilityForLinkage().isAlwaysAvailable()); } if (getModuleContext() == fromModule) return false; if (isAlwaysWeakImported()) return true; if (fromModule->isImportedAsWeakLinked(this->getModuleContext())) return true; auto availability = getAvailabilityForLinkage(); if (availability.isAlwaysAvailable()) return false; auto &ctx = fromModule->getASTContext(); auto deploymentTarget = AvailabilityRange::forDeploymentTarget(ctx); if (ctx.LangOpts.WeakLinkAtTarget) return !availability.isSupersetOf(deploymentTarget); return !deploymentTarget.isContainedIn(availability); } GenericContext::GenericContext(DeclContextKind Kind, DeclContext *Parent, GenericParamList *Params) : _GenericContext(), DeclContext(Kind, Parent) { if (Params) { Params->setDeclContext(this); GenericParamsAndState.setPointerAndInt(Params, GenericParamsState::Parsed); } } ArrayRef GenericContext::getInnermostGenericParamTypes() const { return getGenericSignature().getInnermostGenericParams(); } /// Retrieve the generic requirements. ArrayRef GenericContext::getGenericRequirements() const { return getGenericSignature().getRequirements(); } GenericParamList *GenericContext::getGenericParams() const { return evaluateOrDefault(getASTContext().evaluator, GenericParamListRequest{ const_cast(this)}, nullptr); } GenericParamList *GenericContext::getParsedGenericParams() const { switch (GenericParamsAndState.getInt()) { case GenericParamsState::Parsed: case GenericParamsState::ParsedAndTypeChecked: return GenericParamsAndState.getPointer(); case GenericParamsState::TypeChecked: return nullptr; } } bool GenericContext::hasComputedGenericSignature() const { return GenericSigAndBit.getInt(); } bool GenericContext::isComputingGenericSignature() const { return getASTContext().evaluator.hasActiveRequest( GenericSignatureRequest{const_cast(this)}); } /// If we hit a cycle while building the generic signature, we can't return /// nullptr, since this breaks invariants elsewhere. Instead, build a dummy /// signature where everything is Copyable and Escapable, to avoid spurious /// downstream diagnostics concerning move-only types. static GenericSignature getPlaceholderGenericSignature( ASTContext &ctx, const DeclContext *DC) { SmallVector gpLists; DC->forEachGenericContext([&](GenericParamList *genericParams) { gpLists.push_back(genericParams); }); if (gpLists.empty()) return nullptr; std::reverse(gpLists.begin(), gpLists.end()); for (unsigned i : indices(gpLists)) gpLists[i]->setDepth(i); SmallVector genericParams; SmallVector requirements; for (auto *gpList : gpLists) { for (auto *genericParam : *gpList) { auto type = genericParam->getDeclaredInterfaceType(); genericParams.push_back(type->castTo()); for (auto ip : InvertibleProtocolSet::allKnown()) { auto proto = ctx.getProtocol(getKnownProtocolKind(ip)); requirements.emplace_back(RequirementKind::Conformance, type, proto->getDeclaredInterfaceType()); } } } return GenericSignature::get(genericParams, requirements); } GenericSignature GenericContext::getGenericSignature() const { auto &ctx = getASTContext(); return ctx.evaluator( GenericSignatureRequest{const_cast(this)}, [&ctx, this]() { return getPlaceholderGenericSignature(ctx, this); }); } GenericEnvironment *GenericContext::getGenericEnvironment() const { return getGenericSignature().getGenericEnvironment(); } void GenericContext::setGenericSignature(GenericSignature genericSig) { assert(!GenericSigAndBit.getPointer() && "Generic signature cannot be changed"); getASTContext().evaluator.cacheOutput(GenericSignatureRequest{this}, std::move(genericSig)); } SourceRange GenericContext::getGenericTrailingWhereClauseSourceRange() const { if (const auto *where = getTrailingWhereClause()) return where->getSourceRange(); return SourceRange(); } ImportDecl *ImportDecl::create(ASTContext &Ctx, DeclContext *DC, SourceLoc ImportLoc, ImportKind Kind, SourceLoc KindLoc, ImportPath Path, ClangNode ClangN) { assert(!Path.empty()); assert(Kind == ImportKind::Module || Path.size() > 1); assert(ClangN.isNull() || ClangN.getAsModule() || isa(ClangN.getAsDecl())); size_t Size = totalSizeToAlloc(Path.size()); void *ptr = allocateMemoryForDecl(Ctx, Size, !ClangN.isNull()); auto D = new (ptr) ImportDecl(DC, ImportLoc, Kind, KindLoc, Path); if (ClangN) D->setClangNode(ClangN); auto realNameIfExists = Ctx.getRealModuleName(Path.front().Item, ASTContext::ModuleAliasLookupOption::realNameFromAlias); if (!realNameIfExists.empty()) { D->RealModuleName = realNameIfExists; } return D; } ImportDecl::ImportDecl(DeclContext *DC, SourceLoc ImportLoc, ImportKind K, SourceLoc KindLoc, ImportPath Path) : Decl(DeclKind::Import, DC), ImportLoc(ImportLoc), KindLoc(KindLoc) { Bits.ImportDecl.NumPathElements = Path.size(); assert(Bits.ImportDecl.NumPathElements == Path.size() && "Truncation error"); Bits.ImportDecl.ImportKind = static_cast(K); assert(getImportKind() == K && "not enough bits for ImportKind"); std::uninitialized_copy(Path.begin(), Path.end(), getTrailingObjects()); } ImportKind ImportDecl::getBestImportKind(const ValueDecl *VD) { switch (VD->getKind()) { case DeclKind::Import: case DeclKind::Extension: case DeclKind::PatternBinding: case DeclKind::TopLevelCode: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: case DeclKind::EnumCase: case DeclKind::PoundDiagnostic: case DeclKind::PrecedenceGroup: case DeclKind::Missing: case DeclKind::MissingMember: case DeclKind::MacroExpansion: llvm_unreachable("not a ValueDecl"); case DeclKind::AssociatedType: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::GenericTypeParam: case DeclKind::Subscript: case DeclKind::EnumElement: case DeclKind::Param: llvm_unreachable("not a top-level ValueDecl"); case DeclKind::BuiltinTuple: llvm_unreachable("BuiltinTupleDecl should not end up here"); case DeclKind::Protocol: return ImportKind::Protocol; case DeclKind::Class: return ImportKind::Class; case DeclKind::Enum: return ImportKind::Enum; case DeclKind::Struct: return ImportKind::Struct; case DeclKind::OpaqueType: return ImportKind::Type; case DeclKind::TypeAlias: { Type type = cast(VD)->getDeclaredInterfaceType(); // FIXME: It's necessary to check for existentials because `getAnyNominal` // looks through them. auto canonical = type->getCanonicalType(); if (isa(canonical)) return ImportKind::Type; auto *nominal = canonical->getAnyNominal(); if (!nominal) return ImportKind::Type; return getBestImportKind(nominal); } case DeclKind::Accessor: case DeclKind::Func: return ImportKind::Func; case DeclKind::Var: return ImportKind::Var; case DeclKind::Module: case DeclKind::Macro: return ImportKind::Module; } llvm_unreachable("bad DeclKind"); } std::optional ImportDecl::findBestImportKind(ArrayRef Decls) { assert(!Decls.empty()); ImportKind FirstKind = ImportDecl::getBestImportKind(Decls.front()); // FIXME: Only functions can be overloaded. if (Decls.size() == 1) return FirstKind; if (FirstKind != ImportKind::Func) return std::nullopt; for (auto NextDecl : Decls.slice(1)) { if (ImportDecl::getBestImportKind(NextDecl) != FirstKind) return std::nullopt; } return FirstKind; } ImportPath ImportDecl::getRealImportPath(ImportPath::Builder &scratch) const { assert(scratch.empty() && "scratch ImportPath::Builder must be initially empty"); auto path = getImportPath(); if (RealModuleName.empty()) return path; for (auto elem : path) { if (scratch.empty()) { // Add the real module name instead of its alias scratch.push_back(RealModuleName); } else { // Add the rest if any (access path elements) scratch.push_back(elem.Item); } } return scratch.get(); } ArrayRef ImportDecl::getDecls() const { // If this isn't a scoped import, there's nothing to do. if (getImportKind() == ImportKind::Module) return {}; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ScopedImportLookupRequest{mutableThis}, {}); } AccessLevel ImportDecl::getAccessLevel() const { if (auto attr = getAttrs().getAttribute()) { if (attr->getAccess() == AccessLevel::Open) { // Use a conservative import if the level given is invalid. return AccessLevel::Internal; } else return attr->getAccess(); } auto &LangOpts = getASTContext().LangOpts; if (LangOpts.hasFeature(Feature::InternalImportsByDefault)) { // Swift 6 mode where the default import is internal. return AccessLevel::Internal; } else { return AccessLevel::Public; } } bool ImportDecl::isAccessLevelImplicit() const { if (auto attr = getAttrs().getAttribute()) { return false; } return true; } void NominalTypeDecl::setConformanceLoader(LazyMemberLoader *lazyLoader, uint64_t contextData) { assert(!Bits.NominalTypeDecl.HasLazyConformances && "Already have lazy conformances"); Bits.NominalTypeDecl.HasLazyConformances = true; ASTContext &ctx = getASTContext(); auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, lazyLoader); contextInfo->allConformancesData = contextData; } std::pair NominalTypeDecl::takeConformanceLoaderSlow() { assert(Bits.NominalTypeDecl.HasLazyConformances && "not lazy conformances"); Bits.NominalTypeDecl.HasLazyConformances = false; auto contextInfo = getASTContext().getOrCreateLazyIterableContextData(this, nullptr); return { contextInfo->loader, contextInfo->allConformancesData }; } InheritedEntry::InheritedEntry(const TypeLoc &typeLoc) : InheritedEntry(typeLoc, /*isUnchecked=*/false, /*isRetroactive=*/false, /*isPreconcurrency=*/false) { if (auto typeRepr = typeLoc.getTypeRepr()) { IsUnchecked = typeRepr->findAttrLoc(TypeAttrKind::Unchecked).isValid(); IsRetroactive = typeRepr->findAttrLoc(TypeAttrKind::Retroactive).isValid(); IsPreconcurrency = typeRepr->findAttrLoc(TypeAttrKind::Preconcurrency).isValid(); } } InheritedTypes::InheritedTypes(const TypeDecl *typeDecl) : Decl(typeDecl) { Entries = typeDecl->Inherited; } InheritedTypes::InheritedTypes(const ExtensionDecl *extensionDecl) : Decl(extensionDecl) { Entries = extensionDecl->Inherited; } InheritedTypes::InheritedTypes( llvm::PointerUnion decl) : Decl(decl) { if (auto *typeDecl = decl.dyn_cast()) { Entries = typeDecl->Inherited; } else { Entries = decl.get()->Inherited; } } InheritedTypes::InheritedTypes(const class Decl *decl) { if (auto typeDecl = dyn_cast(decl)) { Decl = typeDecl; Entries = typeDecl->Inherited; } else if (auto extensionDecl = dyn_cast(decl)) { Decl = extensionDecl; Entries = extensionDecl->Inherited; } else { Decl = nullptr; Entries = ArrayRef(); } } ASTContext &InheritedTypes::getASTContext() const { if (auto typeDecl = Decl.dyn_cast()) { return typeDecl->getASTContext(); } else { return Decl.get()->getASTContext(); } } SourceLoc InheritedTypes::getColonLoc() const { if (Entries.size() == 0) return SourceLoc(); SourceLoc precedingTok; if (auto typeDecl = Decl.dyn_cast()) { precedingTok = typeDecl->getNameLoc(); } else { auto *ext = Decl.get(); precedingTok = ext->getSourceRange().End; } auto &ctx = getASTContext(); return Lexer::getLocForEndOfToken(ctx.SourceMgr, precedingTok); } SourceRange InheritedTypes::getRemovalRange(unsigned i) const { auto inheritedClause = getEntries(); auto &ctx = getASTContext(); // If there is just one entry, remove the entire inheritance clause. if (inheritedClause.size() == 1) { SourceLoc end = inheritedClause[i].getSourceRange().End; return SourceRange(getColonLoc(), Lexer::getLocForEndOfToken(ctx.SourceMgr, end)); } // If we're at the first entry, remove from the start of this entry to the // start of the next entry. if (i == 0) { return SourceRange(inheritedClause[i].getSourceRange().Start, inheritedClause[i+1].getSourceRange().Start); } // Otherwise, remove from the end of the previous entry to the end of this // entry. SourceLoc afterPriorLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, inheritedClause[i-1].getSourceRange().End); SourceLoc afterMyEndLoc = Lexer::getLocForEndOfToken(ctx.SourceMgr, inheritedClause[i].getSourceRange().End); return SourceRange(afterPriorLoc, afterMyEndLoc); } Type InheritedTypes::getResolvedType(unsigned i, TypeResolutionStage stage) const { ASTContext &ctx = Decl.is() ? Decl.get()->getASTContext() : Decl.get()->getASTContext(); return evaluateOrDefault(ctx.evaluator, InheritedTypeRequest{Decl, i, stage}, InheritedTypeResult::forDefault()) .getInheritedTypeOrNull(getASTContext()); } ExtensionDecl::ExtensionDecl(SourceLoc extensionLoc, TypeRepr *extendedType, ArrayRef inherited, DeclContext *parent, TrailingWhereClause *trailingWhereClause) : GenericContext(DeclContextKind::ExtensionDecl, parent, nullptr), Decl(DeclKind::Extension, parent), IterableDeclContext(IterableDeclContextKind::ExtensionDecl), ExtensionLoc(extensionLoc), ExtendedTypeRepr(extendedType), Inherited(inherited) { Bits.ExtensionDecl.DefaultAndMaxAccessLevel = 0; Bits.ExtensionDecl.HasLazyConformances = false; setTrailingWhereClause(trailingWhereClause); } ExtensionDecl *ExtensionDecl::create(ASTContext &ctx, SourceLoc extensionLoc, TypeRepr *extendedType, ArrayRef inherited, DeclContext *parent, TrailingWhereClause *trailingWhereClause, ClangNode clangNode) { unsigned size = sizeof(ExtensionDecl); void *declPtr = allocateMemoryForDecl(ctx, size, !clangNode.isNull()); // Construct the extension. auto result = ::new (declPtr) ExtensionDecl(extensionLoc, extendedType, inherited, parent, trailingWhereClause); if (clangNode) result->setClangNode(clangNode); return result; } void ExtensionDecl::setConformanceLoader(LazyMemberLoader *lazyLoader, uint64_t contextData) { assert(!Bits.ExtensionDecl.HasLazyConformances && "Already have lazy conformances"); Bits.ExtensionDecl.HasLazyConformances = true; ASTContext &ctx = getASTContext(); auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, lazyLoader); contextInfo->allConformancesData = contextData; } std::pair ExtensionDecl::takeConformanceLoaderSlow() { assert(Bits.ExtensionDecl.HasLazyConformances && "no conformance loader?"); Bits.ExtensionDecl.HasLazyConformances = false; auto contextInfo = getASTContext().getOrCreateLazyIterableContextData(this, nullptr); return { contextInfo->loader, contextInfo->allConformancesData }; } NominalTypeDecl *ExtensionDecl::getExtendedNominal() const { if (hasBeenBound()) { return ExtendedNominal.getPointer(); } else if (canNeverBeBound()) { return computeExtendedNominal(); } llvm_unreachable( "Extension must have already been bound (by bindExtensions)"); } NominalTypeDecl *ExtensionDecl::computeExtendedNominal() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, ExtendedNominalRequest{const_cast(this)}, nullptr); } bool ExtensionDecl::canNeverBeBound() const { // \c bindExtensions() only looks at valid parents for extensions. return !hasValidParent(); } bool ExtensionDecl::hasValidParent() const { return getDeclContext()->canBeParentOfExtension(); } /// Does the extension's generic signature impose additional generic requirements /// not stated on the extended nominal type itself? bool ExtensionDecl::isConstrainedExtension() const { auto nominal = getExtendedNominal(); if (!nominal) return false; auto typeSig = nominal->getGenericSignature(); if (!typeSig) return false; auto extSig = getGenericSignature(); if (!extSig) return false; // If the generic signature differs from that of the nominal type, it's a // constrained extension. return !typeSig->isEqual(extSig); } /// Is the extension written as an unconstrained extension? This is not the same /// as isConstrainedExtension() in the case where the extended nominal type has /// inverse requirements, because an extension of such a type introduces default /// conformance requirements unless they're suppressed on the extension. /// /// enum Optional where Wrapped: ~Copyable {} /// /// extension Optional {} /// --> isConstrainedExtension(): true /// --> isWrittenWithConstraints(): false /// /// extension Optional where Wrapped: ~Copyable {} /// --> isConstrainedExtension(): false /// --> isWrittenWithConstraints(): true bool ExtensionDecl::isWrittenWithConstraints() const { auto nominal = getExtendedNominal(); if (!nominal) return false; // If there's no generic signature, then it's unconstrained. CanGenericSignature extSig = getGenericSignature().getCanonicalSignature(); if (!extSig) return false; CanGenericSignature typeSig = nominal->getGenericSignature().getCanonicalSignature(); // Get the requirements and inverses for both the extension and type. SmallVector extReqs; SmallVector extInverseReqs; extSig->getRequirementsWithInverses(extReqs, extInverseReqs); SmallVector typeReqs; SmallVector typeInverseReqs; typeSig->getRequirementsWithInverses(typeReqs, typeInverseReqs); // If the non-inverse requirements are different between the extension and // the original type, it's written with constraints. if (extReqs != typeReqs) return true; // If the extension has inverse requirements, then it's written with // constraints. if (!extInverseReqs.empty()) return true; // Otherwise, the extension is written as an unconstrained extension. return false; } bool ExtensionDecl::isInSameDefiningModule() const { auto decl = getExtendedNominal(); auto extensionAlterName = getAlternateModuleName(); auto typeAlterName = decl->getAlternateModuleName(); if (!extensionAlterName.empty()) { if (!typeAlterName.empty()) { // Case I: type and extension are both moved from somewhere else return typeAlterName == extensionAlterName; } else { // Case II: extension alone was moved from somewhere else return extensionAlterName == decl->getParentModule()->getNameStr(); } } else { if (!typeAlterName.empty()) { // Case III: extended type alone was moved from somewhere else return typeAlterName == getParentModule()->getNameStr(); } else { // Case IV: neither of type and extension was moved from somewhere else return getParentModule() == decl->getParentModule(); } } } bool ExtensionDecl::isEquivalentToExtendedContext() const { return isInSameDefiningModule() && !isConstrainedExtension() && !getDeclaredInterfaceType()->isExistentialType(); } AccessLevel ExtensionDecl::getDefaultAccessLevel() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, DefaultAndMaxAccessLevelRequest{const_cast(this)}, {AccessLevel::Private, AccessLevel::Private}).first; } AccessLevel ExtensionDecl::getMaxAccessLevel() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, DefaultAndMaxAccessLevelRequest{const_cast(this)}, {AccessLevel::Private, AccessLevel::Private}).second; } Type ExtensionDecl::getExtendedType() const { ASTContext &ctx = getASTContext(); if (auto type = evaluateOrDefault(ctx.evaluator, ExtendedTypeRequest{const_cast(this)}, Type())) return type; return ErrorType::get(ctx); } bool ExtensionDecl::isAddingConformanceToInvertible() const { const unsigned numEntries = getInherited().size(); for (unsigned i = 0; i < numEntries; ++i) { InheritedTypeRequest request{this, i, TypeResolutionStage::Structural}; auto result = evaluateOrDefault(getASTContext().evaluator, request, InheritedTypeResult::forDefault()); Type inheritedTy; switch (result) { case InheritedTypeResult::Inherited: inheritedTy = result.getInheritedType(); break; case InheritedTypeResult::Suppressed: case InheritedTypeResult::Default: continue; } if (inheritedTy) if (auto kp = inheritedTy->getKnownProtocol()) if (getInvertibleProtocolKind(*kp)) return true; } return false; } bool Decl::isObjCImplementation() const { return getAttrs().hasAttribute(/*AllowInvalid=*/true); } PatternBindingDecl::PatternBindingDecl(SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, unsigned NumPatternEntries, DeclContext *Parent) : Decl(DeclKind::PatternBinding, Parent), StaticLoc(StaticLoc), VarLoc(VarLoc) { Bits.PatternBindingDecl.IsStatic = StaticLoc.isValid(); Bits.PatternBindingDecl.StaticSpelling = static_cast(StaticSpelling); Bits.PatternBindingDecl.NumPatternEntries = NumPatternEntries; } PatternBindingDecl * PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, Pattern *Pat, SourceLoc EqualLoc, Expr *E, DeclContext *Parent) { // We can provide a null context, 'create' will fill it in for us. // FIXME: This seems dubious, see the comment in 'create'. auto PBE = PatternBindingEntry(Pat, EqualLoc, E, /*InitContext*/ nullptr); return create(Ctx, StaticLoc, StaticSpelling, VarLoc, PBE, Parent); } PatternBindingDecl *PatternBindingDecl::createImplicit( ASTContext &Ctx, StaticSpellingKind StaticSpelling, Pattern *Pat, Expr *E, DeclContext *Parent, SourceLoc VarLoc) { auto *Result = create(Ctx, /*StaticLoc*/ SourceLoc(), StaticSpelling, VarLoc, Pat, /*EqualLoc*/ SourceLoc(), E, Parent); Result->setImplicit(); return Result; } PatternBindingDecl *PatternBindingDecl::createForDebugger( ASTContext &Ctx, StaticSpellingKind StaticSpelling, Pattern *Pat, Expr *E, DeclContext *Parent) { auto *Result = createImplicit(Ctx, StaticSpelling, Pat, E, Parent); Result->Bits.PatternBindingDecl.IsDebugger = true; for (auto &entry : Result->getMutablePatternList()) { entry.setFromDebugger(); } return Result; } PatternBindingDecl * PatternBindingDecl::create(ASTContext &Ctx, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, ArrayRef PatternList, DeclContext *Parent) { size_t Size = totalSizeToAlloc(PatternList.size()); void *D = allocateMemoryForDecl(Ctx, Size, /*ClangNode*/false); auto PBD = ::new (D) PatternBindingDecl(StaticLoc, StaticSpelling, VarLoc, PatternList.size(), Parent); // Set up the patterns. std::uninitialized_copy(PatternList.begin(), PatternList.end(), PBD->getTrailingObjects()); for (auto idx : range(PBD->getNumPatternEntries())) { auto *initContext = PBD->getInitContext(idx); // FIXME: We ought to reconsider this since it won't recontextualize any // closures/decls present in the initialization expr. This currently should // only affect implicit code though. if (!initContext && !Parent->isLocalContext()) initContext = PatternBindingInitializer::create(Parent); // We need to call setPattern to ensure the VarDecls in the pattern have // the PatternBindingDecl set as their parent. We also need to call // setInitContext to setup the context. PBD->setPattern(idx, PBD->getPattern(idx)); PBD->setInitContext(idx, initContext); } return PBD; } PatternBindingDecl *PatternBindingDecl::createDeserialized( ASTContext &Ctx, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc VarLoc, unsigned NumPatternEntries, DeclContext *Parent) { size_t Size = totalSizeToAlloc(NumPatternEntries); void *D = allocateMemoryForDecl(Ctx, Size, /*ClangNode*/false); auto PBD = ::new (D) PatternBindingDecl(StaticLoc, StaticSpelling, VarLoc, NumPatternEntries, Parent); for (auto &entry : PBD->getMutablePatternList()) { entry = PatternBindingEntry(/*Pattern*/ nullptr, /*EqualLoc*/ SourceLoc(), /*Init*/ nullptr, /*InitContext*/ nullptr); } return PBD; } PatternBindingInitializer * PatternBindingInitializer::createDeserialized(PatternBindingDecl *PBD, unsigned index) { auto *init = PatternBindingInitializer::create(PBD->getDeclContext()); init->setBinding(PBD, index); return init; } ParamDecl *PatternBindingInitializer::getImplicitSelfDecl() const { if (SelfParam) return SelfParam; if (auto singleVar = getInitializedLazyVar()) { auto DC = singleVar->getDeclContext(); if (DC->isTypeContext()) { auto specifier = (DC->getDeclaredInterfaceType()->hasReferenceSemantics() ? ParamSpecifier::Default : ParamSpecifier::InOut); ASTContext &C = DC->getASTContext(); auto *mutableThis = const_cast(this); auto *LazySelfParam = new (C) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), singleVar->getLoc(), C.Id_self, mutableThis); LazySelfParam->setImplicit(); LazySelfParam->setSpecifier(specifier); LazySelfParam->setInterfaceType(DC->getSelfInterfaceType()); // Lazy members of actors have an isolated 'self', assuming there is // no "nonisolated" attribute. if (auto nominal = DC->getSelfNominalTypeDecl()) { if (nominal->isActor() && !singleVar->getAttrs().hasAttribute()) LazySelfParam->setIsolated(); } mutableThis->SelfParam = LazySelfParam; } } return SelfParam; } void PatternBindingInitializer::setBinding(PatternBindingDecl *binding, unsigned bindingIndex) { assert(binding); assert(!Binding || Binding == binding && "Cannot change the binding after the fact"); assert(!Binding || SpareBits == bindingIndex && "Cannot change the binding index after the fact"); setParent(binding->getDeclContext()); Binding = binding; SpareBits = bindingIndex; } VarDecl *PatternBindingInitializer::getInitializedLazyVar() const { if (auto binding = getBinding()) { if (auto var = binding->getSingleVar()) { if (var->getAttrs().hasAttribute()) return var; } } return nullptr; } unsigned PatternBindingDecl::getPatternEntryIndexForVarDecl(const VarDecl *VD) const { assert(VD && "Cannot find a null VarDecl"); auto List = getPatternList(); if (List.size() == 1) { assert(List[0].getPattern()->containsVarDecl(VD) && "Single entry PatternBindingDecl is set up wrong"); return 0; } unsigned Result = 0; for (auto entry : List) { if (entry.getPattern()->containsVarDecl(VD)) return Result; ++Result; } assert(0 && "PatternBindingDecl doesn't bind the specified VarDecl!"); return ~0U; } Expr *PatternBindingEntry::getOriginalInit() const { return InitContextAndFlags.getInt().contains(PatternFlags::IsText) ? nullptr : InitExpr.originalInit; } SourceRange PatternBindingEntry::getOriginalInitRange() const { if (auto *i = getOriginalInit()) return i->getSourceRange(); return SourceRange(); } void PatternBindingEntry::setOriginalInit(Expr *E) { InitExpr.originalInit = E; InitContextAndFlags.setInt(InitContextAndFlags.getInt() - PatternFlags::IsText); } bool PatternBindingEntry::isInitialized(bool onlyExplicit) const { // Directly initialized. if (getInit() && (!onlyExplicit || getEqualLoc().isValid())) return true; // Initialized via a property wrapper. if (auto var = getPattern()->getSingleVar()) { auto customAttrs = var->getAttachedPropertyWrappers(); if (customAttrs.size() > 0 && customAttrs[0]->hasArgs()) return true; } return false; } void PatternBindingEntry::setInit(Expr *E) { auto F = PatternAndFlags.getInt(); if (E) { PatternAndFlags.setInt(F - Flags::Removed); } else { PatternAndFlags.setInt(F | Flags::Removed); } InitExpr.initAfterSynthesis.setPointer(E); InitContextAndFlags.setInt(InitContextAndFlags.getInt() - PatternFlags::IsText); } VarDecl *PatternBindingEntry::getAnchoringVarDecl() const { SmallVector variables; getPattern()->collectVariables(variables); if (variables.empty()) return nullptr; return variables[0]; } SourceLoc PatternBindingEntry::getLastAccessorEndLoc() const { SourceLoc lastAccessorEnd; getPattern()->forEachVariable([&](VarDecl *var) { auto accessorsEndLoc = var->getBracesRange().End; if (accessorsEndLoc.isValid()) lastAccessorEnd = accessorsEndLoc; }); return lastAccessorEnd; } SourceLoc PatternBindingEntry::getStartLoc() const { return getPattern()->getStartLoc(); } SourceLoc PatternBindingEntry::getEndLoc(bool omitAccessors) const { // Accessors are last if (!omitAccessors) { const auto lastAccessorEnd = getLastAccessorEndLoc(); if (lastAccessorEnd.isValid()) return lastAccessorEnd; } const auto initEnd = getOriginalInitRange().End; if (initEnd.isValid()) return initEnd; return getPattern()->getEndLoc(); } SourceRange PatternBindingEntry::getSourceRange(bool omitAccessors) const { const SourceLoc startLoc = getStartLoc(); if (startLoc.isInvalid()) return SourceRange(); const SourceLoc endLoc = getEndLoc(omitAccessors); if (endLoc.isInvalid()) return SourceRange(); return SourceRange(startLoc, endLoc); } bool PatternBindingEntry::hasInitStringRepresentation() const { if (InitContextAndFlags.getInt().contains(PatternFlags::IsText)) return !InitStringRepresentation.empty(); return getOriginalInit() && getOriginalInit()->getSourceRange().isValid(); } StringRef PatternBindingEntry::getInitStringRepresentation( SmallVectorImpl &scratch) const { assert(hasInitStringRepresentation() && "must check if pattern has string representation"); if (InitContextAndFlags.getInt().contains(PatternFlags::IsText) && !InitStringRepresentation.empty()) return InitStringRepresentation; auto &ctx = getAnchoringVarDecl()->getASTContext(); auto init = getOriginalInit(); return extractInlinableText(ctx, init, scratch); } SourceRange PatternBindingDecl::getSourceRange() const { SourceLoc startLoc = getStartLoc(); SourceLoc endLoc = getPatternList().empty() ? SourceLoc() : getPatternList().back().getSourceRange().End; if (startLoc.isValid() != endLoc.isValid()) return SourceRange(); return { startLoc, endLoc }; } static StaticSpellingKind getCorrectStaticSpellingForDecl(const Decl *D) { if (auto classDecl = D->getDeclContext()->getSelfClassDecl()) { if (!classDecl->isActor()) return StaticSpellingKind::KeywordClass; } return StaticSpellingKind::KeywordStatic; } StaticSpellingKind PatternBindingDecl::getCorrectStaticSpelling() const { if (!isStatic()) return StaticSpellingKind::None; if (getStaticSpelling() != StaticSpellingKind::None) return getStaticSpelling(); return getCorrectStaticSpellingForDecl(this); } bool PatternBindingDecl::isAsyncLet() const { if (auto var = getAnchoringVarDecl(0)) return var->isAsyncLet(); // Check for "async let _: = " pattern. auto *pattern = getPatternList()[0].getPattern(); if (auto *typedPattern = dyn_cast(pattern)) { auto *anyPattern = dyn_cast(typedPattern->getSubPattern()); return anyPattern && anyPattern->isAsyncLet(); } // Check for "async let _ = " pattern. if (auto *anyPattern = dyn_cast(pattern)) { return anyPattern->isAsyncLet(); } return false; } ActorIsolation PatternBindingDecl::getInitializerIsolation(unsigned i) const { auto *var = getPatternList()[i].getAnchoringVarDecl(); if (!var) return ActorIsolation::forUnspecified(); return var->getInitializerIsolation(); } Expr *PatternBindingDecl::getContextualizedInit(unsigned i) const { auto *mutableThis = const_cast(this); return evaluateOrDefault( getASTContext().evaluator, PatternBindingCheckedAndContextualizedInitRequest{mutableThis, i}, nullptr); } Expr *PatternBindingDecl::getCheckedAndContextualizedInit(unsigned i) const { auto *expr = getContextualizedInit(i); if (auto *initContext = getInitContext(i)) { // Property wrapper isolation is checked separately while // synthesizing the backing property wrapper initializer. auto *var = getSingleVar(); if (!(var && var->hasAttachedPropertyWrapper())) { (void)getInitializerIsolation(i); } // Effects checking for 'async' needs actor isolation to be // computed. Always run effects checking after the actor // isolation checker. evaluateOrDefault( getASTContext().evaluator, CheckInitEffectsRequest{initContext, expr}, {}); } return expr; } Expr *PatternBindingDecl::getCheckedAndContextualizedExecutableInit( unsigned i) const { (void)getCheckedAndContextualizedInit(i); return getExecutableInit(i); } bool PatternBindingDecl::hasStorage() const { // Walk the pattern, to check to see if any of the VarDecls included in it // have storage. for (auto entry : getPatternList()) if (entry.getPattern()->hasStorage()) return true; return false; } const PatternBindingEntry * PatternBindingDecl::getCheckedPatternBindingEntry(unsigned i) const { return evaluateOrDefault( getASTContext().evaluator, PatternBindingEntryRequest{const_cast(this), i}, nullptr); } void PatternBindingDecl::setPattern(unsigned i, Pattern *P, bool isFullyValidated) { auto PatternList = getMutablePatternList(); PatternList[i].setPattern(P); // Make sure that any VarDecl's contained within the pattern know about this // PatternBindingDecl as their parent. if (P) { P->forEachVariable([&](VarDecl *VD) { if (!VD->isCaptureList()) VD->setParentPatternBinding(this); }); if (isFullyValidated) PatternList[i].setFullyValidated(); } } VarDecl *PatternBindingDecl::getSingleVar() const { if (getNumPatternEntries() == 1) return getPatternList()[0].getPattern()->getSingleVar(); return nullptr; } VarDecl *PatternBindingDecl::getAnchoringVarDecl(unsigned i) const { return getPatternList()[i].getAnchoringVarDecl(); } bool VarDecl::isInitExposedToClients() const { // 'lazy' initializers are emitted inside the getter, which is never // @inlinable. if (getAttrs().hasAttribute()) return false; return hasInitialValue() && isLayoutExposedToClients(); } bool VarDecl::isLayoutExposedToClients() const { auto parent = dyn_cast(getDeclContext()); if (!parent) return false; if (isStatic()) return false; auto nominalAccess = parent->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); if (!nominalAccess.isPublic()) return false; if (!parent->getAttrs().hasAttribute() && !parent->getAttrs().hasAttribute()) return false; if (!hasStorage() && !getAttrs().hasAttribute() && !hasAttachedPropertyWrapper()) { return false; } return true; } /// Check whether the given type representation will be /// default-initializable. static bool isDefaultInitializable(const TypeRepr *typeRepr, ASTContext &ctx) { // Look through most attributes. if (const auto attributed = dyn_cast(typeRepr)) { // Ownership kinds have optionalness requirements. // FIXME: this is checking for *SIL* ownership; normal weak/unowned/etc. // are decl attributes. Is this actually an important check to do? if (optionalityOf(attributed->getSILOwnership()) == ReferenceOwnershipOptionality::Required) return true; return isDefaultInitializable(attributed->getTypeRepr(), ctx); } // Optional types are default-initializable. if (isa(typeRepr) || isa(typeRepr)) return true; // Also support the desugared 'Optional' spelling. if (!ctx.isSwiftVersionAtLeast(5)) { if (typeRepr->isSimpleUnqualifiedIdentifier(ctx.Id_Void)) { return true; } if (auto *unqualIdentRepr = dyn_cast(typeRepr)) { if (unqualIdentRepr->getNumGenericArgs() == 1 && unqualIdentRepr->getNameRef().getBaseIdentifier() == ctx.Id_Optional) return true; } } // Tuple types are default-initializable if all of their element // types are. if (const auto tuple = dyn_cast(typeRepr)) { for (const auto &elt : tuple->getElements()) { if (!isDefaultInitializable(elt.Type, ctx)) return false; } return true; } // Not default initializable. return false; } // @NSManaged properties never get default initialized, nor do debugger // variables and immutable properties. bool Pattern::isNeverDefaultInitializable() const { bool result = false; forEachVariable([&](const VarDecl *var) { if (var->getAttrs().hasAttribute()) return; if (var->isDebuggerVar() || var->isLet()) result = true; }); return result; } bool PatternBindingDecl::isDefaultInitializableViaPropertyWrapper(unsigned i) const { if (auto singleVar = getSingleVar()) { if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) { if (wrapperInfo.defaultInit) return true; } } return false; } bool PatternBindingDecl::isDefaultInitializable(unsigned i) const { const auto entry = getPatternList()[i]; // If it has an initializer expression, this is trivially true. if (entry.isInitialized()) return true; // If the outermost attached property wrapper vends an `init()`, use that // for default initialization. if (isDefaultInitializableViaPropertyWrapper(i)) return true; // If one of the attached wrappers is missing a wrappedValue // initializer, cannot default-initialize. if (auto singleVar = getSingleVar()) { if (auto wrapperInfo = singleVar->getAttachedPropertyWrapperTypeInfo(0)) { if (!singleVar->allAttachedPropertyWrappersHaveWrappedValueInit()) return false; } } if (entry.getPattern()->isNeverDefaultInitializable()) return false; auto &ctx = getASTContext(); // If the pattern is typed as optional (or tuples thereof), it is // default initializable. if (const auto typedPattern = dyn_cast(entry.getPattern())) { if (const auto typeRepr = typedPattern->getTypeRepr()) { if (::isDefaultInitializable(typeRepr, ctx)) return true; } else if (typedPattern->isImplicit()) { // Lazy vars have implicit storage assigned to back them. Because the // storage is implicit, the pattern is typed and has a TypeLoc, but not a // TypeRepr. // // All lazy storage is implicitly default initializable, though, because // lazy backing storage is optional. if (const auto *varDecl = typedPattern->getSingleVar()) { // Lazy storage is never user accessible. if (!varDecl->isUserAccessible()) { if (typedPattern->hasType() && typedPattern->getType()->getOptionalObjectType()) { return true; } } } } } // Otherwise, we can't default initialize this binding. return false; } bool PatternBindingDecl::isComputingPatternBindingEntry( const VarDecl *vd) const { unsigned i = getPatternEntryIndexForVarDecl(vd); return getASTContext().evaluator.hasActiveRequest( PatternBindingEntryRequest{const_cast(this), i}); } bool PatternBindingDecl::isExplicitlyInitialized(unsigned i) const { const auto &entry = getPatternList()[i]; return entry.isInitialized(/*onlyExplicit=*/true); } SourceLoc PatternBindingDecl::getEqualLoc(unsigned i) const { const auto &entry = getPatternList()[i]; return entry.getEqualLoc(); } SourceLoc TopLevelCodeDecl::getStartLoc() const { return Body ? Body->getStartLoc() : SourceLoc(); } SourceRange TopLevelCodeDecl::getSourceRange() const { return Body? Body->getSourceRange() : SourceRange(); } static bool isPolymorphic(const AbstractStorageDecl *storage) { if (storage->shouldUseObjCDispatch()) return true; // Imported declarations behave like they are dynamic, even if they're // not marked as such explicitly. if (storage->isObjC() && storage->hasClangNode()) return true; if (auto *classDecl = dyn_cast(storage->getDeclContext())) { // Accesses to members of foreign reference types should be made directly // to storage as these are references to clang records which are not allowed // to have dynamic dispatch. if (storage->isFinal() || classDecl->isFinal() || classDecl->isForeignReferenceType()) return false; return true; } if (isa(storage->getDeclContext())) return true; return false; } /// Returns true iff a defer's storage access kind should always /// match the access kind of its immediately enclosing function. /// /// In Swift 5 and earlier, this was not true, meaning that property observers, /// etc, would be invoked in initializers or deinitializers if a property access /// happens within a defer, but not when outside the defer. static bool deferMatchesEnclosingAccess(const FuncDecl *defer) { assert(defer->isDeferBody()); // In Swift 6+, then yes. if (defer->getASTContext().isSwiftVersionAtLeast(6)) return true; // If the defer is part of a function that is a member of an actor or // concurrency-aware type, then yes. if (auto *deferContext = defer->getParent()) { if (auto *funcContext = deferContext->getParent()) { if (auto *type = funcContext->getSelfNominalTypeDecl()) { if (type->isAnyActor()) return true; auto isolation = getActorIsolation(type); switch (isolation) { case ActorIsolation::Unspecified: case ActorIsolation::NonisolatedUnsafe: break; case ActorIsolation::GlobalActor: if (isolation.preconcurrency()) break; return true; case ActorIsolation::ActorInstance: case ActorIsolation::Nonisolated: case ActorIsolation::Erased: // really can't happen return true; } } } } return false; } static bool isDirectToStorageAccess(const DeclContext *UseDC, const VarDecl *var, bool isAccessOnSelf) { if (!var->hasStorage()) return false; auto *AFD = dyn_cast_or_null(UseDC); if (AFD == nullptr) return false; // Check if this is a function representing a defer. if (auto *func = dyn_cast(AFD)) if (func->isDeferBody() && deferMatchesEnclosingAccess(func)) return isDirectToStorageAccess(func->getParent(), var, isAccessOnSelf); // The property reference is for immediate class, not a derived class. if (AFD->getParent()->getSelfNominalTypeDecl() != var->getDeclContext()->getSelfNominalTypeDecl()) return false; // If the storage is resilient, we cannot access it directly at all. if (var->isResilient(UseDC->getParentModule(), UseDC->getResilienceExpansion())) return var->getModuleContext()->getBypassResilience(); if (isa(AFD) || isa(AFD)) { // The access must also be a member access on 'self' in all language modes. if (!isAccessOnSelf) return false; return true; } else if (auto *accessor = dyn_cast(AFD)) { // The accessor must be for the variable itself. if (accessor->getStorage() != var) return false; // In Swift 5 and later, the access must also be a member access on 'self'. if (!isAccessOnSelf && var->getDeclContext()->isTypeContext() && var->getASTContext().isSwiftVersionAtLeast(5)) return false; // As a special case, 'read' and 'modify' coroutines with forced static // dispatch must use ordinary semantics, so that the 'modify' coroutine for a // 'dynamic' property uses Objective-C message sends and not direct access to // storage. if (accessor->hasForcedStaticDispatch()) return false; return true; } return false; } /// Determines the access semantics to use in a DeclRefExpr or /// MemberRefExpr use of this value in the specified context. AccessSemantics ValueDecl::getAccessSemanticsFromContext(const DeclContext *UseDC, bool isAccessOnSelf) const { if (auto *var = dyn_cast(this)) if (isDirectToStorageAccess(UseDC, var, isAccessOnSelf)) return AccessSemantics::DirectToStorage; // Otherwise, it's a semantically normal access. The client should be // able to figure out the most efficient way to do this access. return AccessSemantics::Ordinary; } static AccessStrategy getDirectReadAccessStrategy(const AbstractStorageDecl *storage) { switch (storage->getReadImpl()) { case ReadImplKind::Stored: return AccessStrategy::getStorage(); case ReadImplKind::Inherited: // TODO: maybe add a specific strategy for this? return AccessStrategy::getAccessor(AccessorKind::Get, /*dispatch*/ false); case ReadImplKind::Get: return AccessStrategy::getAccessor(AccessorKind::Get, /*dispatch*/ false); case ReadImplKind::Address: return AccessStrategy::getAccessor(AccessorKind::Address, /*dispatch*/ false); case ReadImplKind::Read: return AccessStrategy::getAccessor(AccessorKind::Read, /*dispatch*/ false); case ReadImplKind::Read2: return AccessStrategy::getAccessor(AccessorKind::Read2, /*dispatch*/ false); } llvm_unreachable("bad impl kind"); } static AccessStrategy getDirectWriteAccessStrategy(const AbstractStorageDecl *storage) { switch (storage->getWriteImpl()) { case WriteImplKind::Immutable: { if (storage->hasInitAccessor()) return AccessStrategy::getAccessor(AccessorKind::Init, /*dispatch=*/false); assert(isa(storage) && cast(storage)->isLet() && "mutation of a immutable variable that isn't a let"); return AccessStrategy::getStorage(); } case WriteImplKind::Stored: return AccessStrategy::getStorage(); case WriteImplKind::StoredWithObservers: // TODO: maybe add a specific strategy for this? return AccessStrategy::getAccessor(AccessorKind::Set, /*dispatch*/ false); case WriteImplKind::InheritedWithObservers: // TODO: maybe add a specific strategy for this? return AccessStrategy::getAccessor(AccessorKind::Set, /*dispatch*/ false); case WriteImplKind::Set: return AccessStrategy::getAccessor(AccessorKind::Set, /*dispatch*/ false); case WriteImplKind::MutableAddress: return AccessStrategy::getAccessor(AccessorKind::MutableAddress, /*dispatch*/ false); case WriteImplKind::Modify: return AccessStrategy::getAccessor(AccessorKind::Modify, /*dispatch*/ false); case WriteImplKind::Modify2: return AccessStrategy::getAccessor(AccessorKind::Modify2, /*dispatch*/ false); } llvm_unreachable("bad impl kind"); } static AccessStrategy getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch); static AccessStrategy getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch); static AccessStrategy getDirectReadWriteAccessStrategy(const AbstractStorageDecl *storage) { switch (storage->getReadWriteImpl()) { case ReadWriteImplKind::Immutable: assert(isa(storage) && cast(storage)->isLet() && "mutation of a immutable variable that isn't a let"); return AccessStrategy::getStorage(); case ReadWriteImplKind::Stored: { // If the storage isDynamic (and not @objc) use the accessors. if (storage->shouldUseNativeDynamicDispatch()) return AccessStrategy::getMaterializeToTemporary( getOpaqueReadAccessStrategy(storage, false), getOpaqueWriteAccessStrategy(storage, false)); return AccessStrategy::getStorage(); } case ReadWriteImplKind::MutableAddress: return AccessStrategy::getAccessor(AccessorKind::MutableAddress, /*dispatch*/ false); case ReadWriteImplKind::Modify: return AccessStrategy::getAccessor(AccessorKind::Modify, /*dispatch*/ false); case ReadWriteImplKind::Modify2: return AccessStrategy::getAccessor(AccessorKind::Modify2, /*dispatch*/ false); case ReadWriteImplKind::StoredWithDidSet: case ReadWriteImplKind::InheritedWithDidSet: if (storage->requiresOpaqueModify2Coroutine() && storage->getParsedAccessor(AccessorKind::DidSet)->isSimpleDidSet()) { return AccessStrategy::getAccessor(AccessorKind::Modify2, /*dispatch*/ false); } else if (storage->requiresOpaqueModifyCoroutine() && storage->getParsedAccessor(AccessorKind::DidSet) ->isSimpleDidSet()) { return AccessStrategy::getAccessor(AccessorKind::Modify, /*dispatch*/ false); } else { return AccessStrategy::getMaterializeToTemporary( getDirectReadAccessStrategy(storage), getDirectWriteAccessStrategy(storage)); } case ReadWriteImplKind::MaterializeToTemporary: return AccessStrategy::getMaterializeToTemporary( getDirectReadAccessStrategy(storage), getDirectWriteAccessStrategy(storage)); } llvm_unreachable("bad impl kind"); } static AccessStrategy getOpaqueReadAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) { if (storage->requiresOpaqueRead2Coroutine()) return AccessStrategy::getAccessor(AccessorKind::Read2, dispatch); if (storage->requiresOpaqueReadCoroutine()) return AccessStrategy::getAccessor(AccessorKind::Read, dispatch); return AccessStrategy::getAccessor(AccessorKind::Get, dispatch); } static AccessStrategy getOpaqueWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) { if (storage->hasInitAccessor() && !storage->getAccessor(AccessorKind::Set)) return AccessStrategy::getAccessor(AccessorKind::Init, dispatch); return AccessStrategy::getAccessor(AccessorKind::Set, dispatch); } static AccessStrategy getOpaqueReadWriteAccessStrategy(const AbstractStorageDecl *storage, bool dispatch) { if (storage->requiresOpaqueModify2Coroutine()) return AccessStrategy::getAccessor(AccessorKind::Modify2, dispatch); if (storage->requiresOpaqueModifyCoroutine()) return AccessStrategy::getAccessor(AccessorKind::Modify, dispatch); return AccessStrategy::getMaterializeToTemporary( getOpaqueReadAccessStrategy(storage, dispatch), getOpaqueWriteAccessStrategy(storage, dispatch)); } static AccessStrategy getOpaqueAccessStrategy(const AbstractStorageDecl *storage, AccessKind accessKind, bool dispatch) { switch (accessKind) { case AccessKind::Read: return getOpaqueReadAccessStrategy(storage, dispatch); case AccessKind::Write: return getOpaqueWriteAccessStrategy(storage, dispatch); case AccessKind::ReadWrite: return getOpaqueReadWriteAccessStrategy(storage, dispatch); } llvm_unreachable("bad access kind"); } AccessStrategy AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics, AccessKind accessKind, ModuleDecl *module, ResilienceExpansion expansion) const { switch (semantics) { case AccessSemantics::DirectToStorage: assert(hasStorage() || getASTContext().Diags.hadAnyError()); return AccessStrategy::getStorage(); case AccessSemantics::DistributedThunk: return AccessStrategy::getDistributedThunkDispatchStrategy(); case AccessSemantics::Ordinary: // Skip these checks for local variables, both because they're unnecessary // and because we won't necessarily have computed access. if (!getDeclContext()->isLocalContext()) { // If the property is defined in a non-final class or a protocol, the // accessors are dynamically dispatched, and we cannot do direct access. if (isPolymorphic(this)) return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ true); if (shouldUseNativeDynamicDispatch()) return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false); // If the storage is resilient from the given module and resilience // expansion, we cannot use direct access. // // If we end up here with a stored property of a type that's resilient // from some resilience domain, we cannot do direct access. // // As an optimization, we do want to perform direct accesses of stored // properties declared inside the same resilience domain as the access // context. // // This is done by using DirectToStorage semantics above, with the // understanding that the access semantics are with respect to the // resilience domain of the accessor's caller. bool resilient; if (module) resilient = isResilient(module, expansion); else resilient = isResilient(); if (resilient) return getOpaqueAccessStrategy(this, accessKind, /*dispatch*/ false); } LLVM_FALLTHROUGH; case AccessSemantics::DirectToImplementation: switch (accessKind) { case AccessKind::Read: return getDirectReadAccessStrategy(this); case AccessKind::Write: return getDirectWriteAccessStrategy(this); case AccessKind::ReadWrite: return getDirectReadWriteAccessStrategy(this); } llvm_unreachable("bad access kind"); } llvm_unreachable("bad access semantics"); } bool AbstractStorageDecl::requiresOpaqueAccessors() const { // Subscripts always require opaque accessors, so don't even kick off // a request. auto *var = dyn_cast(this); if (var == nullptr) return true; ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, RequiresOpaqueAccessorsRequest{const_cast(var)}, false); } bool AbstractStorageDecl::requiresOpaqueAccessor(AccessorKind kind) const { switch (kind) { case AccessorKind::Get: case AccessorKind::DistributedGet: return requiresOpaqueGetter(); case AccessorKind::Set: return requiresOpaqueSetter(); case AccessorKind::Read: return requiresOpaqueReadCoroutine(); case AccessorKind::Read2: return requiresOpaqueRead2Coroutine(); case AccessorKind::Modify: return requiresOpaqueModifyCoroutine(); case AccessorKind::Modify2: return requiresOpaqueModify2Coroutine(); // Other accessors are never part of the opaque-accessors set. #define OPAQUE_ACCESSOR(ID, KEYWORD) #define ACCESSOR(ID) \ case AccessorKind::ID: #include "swift/AST/AccessorKinds.def" return false; } llvm_unreachable("bad accessor kind"); } bool AbstractStorageDecl::requiresOpaqueReadCoroutine() const { ASTContext &ctx = getASTContext(); if (ctx.LangOpts.hasFeature(Feature::CoroutineAccessors)) return requiresCorrespondingUnderscoredCoroutineAccessor( AccessorKind::Read2); return getOpaqueReadOwnership() != OpaqueReadOwnership::Owned; } bool AbstractStorageDecl::requiresOpaqueRead2Coroutine() const { ASTContext &ctx = getASTContext(); if (!ctx.LangOpts.hasFeature(Feature::CoroutineAccessors)) return false; return getOpaqueReadOwnership() != OpaqueReadOwnership::Owned; } bool AbstractStorageDecl::requiresOpaqueModifyCoroutine() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, RequiresOpaqueModifyCoroutineRequest{ const_cast(this), /*isUnderscored=*/true}, false); } bool AbstractStorageDecl::requiresOpaqueModify2Coroutine() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, RequiresOpaqueModifyCoroutineRequest{ const_cast(this), /*isUnderscored=*/false}, false); } AccessorDecl *AbstractStorageDecl::getSynthesizedAccessor(AccessorKind kind) const { if (auto *accessor = getAccessor(kind)) return accessor; ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, SynthesizeAccessorRequest{const_cast(this), kind}, nullptr); } AccessorDecl *AbstractStorageDecl::getEffectfulGetAccessor() const { if (getAllAccessors().size() != 1) return nullptr; if (auto accessor = getAccessor(AccessorKind::Get)) if (accessor->hasAsync() || accessor->hasThrows()) return accessor; return nullptr; } bool AbstractStorageDecl::isLessEffectfulThan(AbstractStorageDecl const* other, EffectKind kind) const { bool allowedByOther = false; if (auto otherGetter = other->getEffectfulGetAccessor()) allowedByOther = otherGetter->hasEffect(kind); if (auto getter = getEffectfulGetAccessor()) if (getter->hasEffect(kind) && !allowedByOther) return false; // has the effect when other does not; it's more effectful! return true; // OK } AccessorDecl *AbstractStorageDecl::getOpaqueAccessor(AccessorKind kind) const { auto *accessor = getAccessor(kind); if (accessor && !accessor->isImplicit()) return accessor; if (!requiresOpaqueAccessors()) return nullptr; if (!requiresOpaqueAccessor(kind)) return nullptr; return getSynthesizedAccessor(kind); } ArrayRef AbstractStorageDecl::getOpaqueAccessors( llvm::SmallVectorImpl &scratch) const { visitOpaqueAccessors([&](AccessorDecl *D) { scratch.push_back(D); }); return scratch; } bool AbstractStorageDecl::hasParsedAccessors() const { for (auto *accessor : getAllAccessors()) if (!accessor->isImplicit()) return true; return false; } AccessorDecl *AbstractStorageDecl::getParsedAccessor(AccessorKind kind) const { auto *accessor = getAccessor(kind); if (accessor && !accessor->isImplicit()) return accessor; return nullptr; } void AbstractStorageDecl::visitParsedAccessors( llvm::function_ref visit) const { for (auto *accessor : getAllAccessors()) if (!accessor->isImplicit()) visit(accessor); } void AbstractStorageDecl::visitEmittedAccessors( llvm::function_ref visit) const { visitParsedAccessors(visit); visitOpaqueAccessors([&](AccessorDecl *accessor) { if (accessor->isImplicit()) visit(accessor); }); } void AbstractStorageDecl::visitExpectedOpaqueAccessors( llvm::function_ref visit) const { if (!requiresOpaqueAccessors()) return; if (requiresOpaqueGetter()) visit(AccessorKind::Get); if (requiresOpaqueReadCoroutine()) visit(AccessorKind::Read); if (requiresOpaqueRead2Coroutine()) visit(AccessorKind::Read2); // All mutable storage should have a setter. if (requiresOpaqueSetter()) visit(AccessorKind::Set); // Include the modify coroutine if it's required. if (requiresOpaqueModifyCoroutine()) visit(AccessorKind::Modify); if (requiresOpaqueModify2Coroutine()) visit(AccessorKind::Modify2); } void AbstractStorageDecl::visitOpaqueAccessors( llvm::function_ref visit) const { visitExpectedOpaqueAccessors([&](AccessorKind kind) { auto accessor = getSynthesizedAccessor(kind); assert(!accessor->hasForcedStaticDispatch() && "opaque accessor with forced static dispatch?"); visit(accessor); }); } static bool hasPrivateOrFilePrivateFormalAccess(const Decl *D) { if (auto *VD = dyn_cast(D)) return VD->getFormalAccess() <= AccessLevel::FilePrivate; return isa(D); } /// Returns true if one of the ancestor DeclContexts of this ValueDecl is either /// marked private or fileprivate or is a local context. static bool isInPrivateOrLocalContext(const Decl *D) { const DeclContext *DC = D->getDeclContext(); if (!DC->isTypeContext()) { assert((DC->isModuleScopeContext() || DC->isLocalContext()) && "unexpected context kind"); return DC->isLocalContext(); } auto *nominal = DC->getSelfNominalTypeDecl(); if (nominal == nullptr) return false; if (hasPrivateOrFilePrivateFormalAccess(nominal)) return true; return isInPrivateOrLocalContext(nominal); } bool Decl::isOutermostPrivateOrFilePrivateScope() const { return hasPrivateOrFilePrivateFormalAccess(this) && !isInPrivateOrLocalContext(this); } bool AbstractStorageDecl::isStrictlyResilient() const { return isResilient() && !getModuleContext()->allowNonResilientAccess(); } bool AbstractStorageDecl::isResilient() const { // Check for an explicit @_fixed_layout attribute. if (getAttrs().hasAttribute()) return false; // If we're an instance property of a nominal type, query the type. if (!isStatic()) if (auto *nominalDecl = getDeclContext()->getSelfNominalTypeDecl()) return nominalDecl->isResilient(); // Non-public global and static variables always have a // fixed layout. auto accessScope = getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); if (!accessScope.isPublicOrPackage()) return false; return getModuleContext()->isResilient(); } bool AbstractStorageDecl::isResilient(ModuleDecl *M, ResilienceExpansion expansion) const { switch (expansion) { case ResilienceExpansion::Minimal: return isResilient(); case ResilienceExpansion::Maximal: if (M == getModuleContext()) return false; return isResilient(); } llvm_unreachable("bad resilience expansion"); } bool AbstractStorageDecl::isValidKeyPathComponent() const { // Check whether we're an ABI compatible override of another property. If we // are, then the key path should refer to the base decl instead. auto &ctx = getASTContext(); auto isABICompatibleOverride = evaluateOrDefault( ctx.evaluator, IsABICompatibleOverrideRequest{const_cast(this)}, false); return !isABICompatibleOverride; } bool AbstractStorageDecl::isGetterMutating() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsGetterMutatingRequest{const_cast(this)}, {}); } bool AbstractStorageDecl::isSetterMutating() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsSetterMutatingRequest{const_cast(this)}, {}); } StorageMutability AbstractStorageDecl::mutability(const DeclContext *useDC, std::optional base ) const { if (auto vd = dyn_cast(this)) return vd->mutability(useDC, base); auto sd = cast(this); return sd->supportsMutation() ? StorageMutability::Mutable : StorageMutability::Immutable; } /// Determine the mutability of this storage declaration when /// accessed from a given declaration context in Swift. /// /// This method differs only from 'mutability()' in its handling of /// 'optional' storage requirements, which lack support for direct /// writes in Swift. StorageMutability AbstractStorageDecl::mutabilityInSwift( const DeclContext *useDC, std::optional base ) const { // TODO: Writing to an optional storage requirement is not supported in Swift. if (getAttrs().hasAttribute()) { return StorageMutability::Immutable; } return mutability(useDC, base); } OpaqueReadOwnership AbstractStorageDecl::getOpaqueReadOwnership() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, OpaqueReadOwnershipRequest{const_cast(this)}, {}); } bool ValueDecl::isInstanceMember() const { DeclContext *DC = getDeclContext(); if (!DC->isTypeContext()) return false; switch (getKind()) { case DeclKind::Import: case DeclKind::Extension: case DeclKind::PatternBinding: case DeclKind::EnumCase: case DeclKind::TopLevelCode: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: case DeclKind::PoundDiagnostic: case DeclKind::PrecedenceGroup: case DeclKind::Missing: case DeclKind::MissingMember: case DeclKind::MacroExpansion: llvm_unreachable("Not a ValueDecl"); case DeclKind::Class: case DeclKind::Enum: case DeclKind::Protocol: case DeclKind::Struct: case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::OpaqueType: // Types are not instance members. return false; case DeclKind::Constructor: // Constructors are not instance members. return false; case DeclKind::Destructor: // Destructors are technically instance members, although they // can't actually be referenced as such. return true; case DeclKind::Func: case DeclKind::Accessor: // Non-static methods are instance members. return !cast(this)->isStatic(); case DeclKind::EnumElement: case DeclKind::Param: // enum elements and function parameters are not instance members. return false; case DeclKind::Subscript: case DeclKind::Var: // Non-static variables and subscripts are instance members. return !cast(this)->isStatic(); case DeclKind::Module: // Modules are never instance members. return false; case DeclKind::Macro: // Macros are never instance members. return false; case DeclKind::BuiltinTuple: llvm_unreachable("BuiltinTupleDecl should not end up here"); } llvm_unreachable("bad DeclKind"); } bool ValueDecl::hasLocalDiscriminator() const { // Generic parameters and unnamed parameters never have local discriminators. if (isa(this) || (isa(this) && !hasName())) return false; // Opaque types never have local discriminators. if (isa(this)) return false; // Accessors never have local discriminators. if (isa(this)) return false; // Implicit and unnamed declarations never have local discriminators. if (getBaseName().isSpecial()) return false; // If we are not in a local context, there's nothing to do. if (!getDeclContext()->isLocalContext()) return false; return true; } unsigned ValueDecl::getLocalDiscriminator() const { // If we have already assigned a local discriminator, we're done. if (LocalDiscriminator != InvalidDiscriminator) return LocalDiscriminator; // If this declaration does not have a local discriminator, use 0 as a // stand-in. if (!hasLocalDiscriminator()) return 0; // Assign local discriminators in this context. ASTContext &ctx = getASTContext(); evaluateOrDefault( ctx.evaluator, LocalDiscriminatorsRequest{getDeclContext()}, InvalidDiscriminator); // If we don't have a discriminator, and either // 1. We have ill-formed code and we're able to assign a discriminator, or // 2. We are in a macro expansion buffer // // then assign the next discriminator now. if (LocalDiscriminator == InvalidDiscriminator && (ctx.Diags.hadAnyError() || (getLoc().isValid() && getModuleContext() ->getSourceFileContainingLocation(getLoc()) ->getFulfilledMacroRole() != std::nullopt))) { auto discriminator = ctx.getNextDiscriminator(getDeclContext()); ctx.setMaxAssignedDiscriminator(getDeclContext(), discriminator + 1); const_cast(this)->LocalDiscriminator = discriminator; } assert(LocalDiscriminator != InvalidDiscriminator); return LocalDiscriminator; } void ValueDecl::setLocalDiscriminator(unsigned index) { assert(hasLocalDiscriminator()); assert(LocalDiscriminator == InvalidDiscriminator && "LocalDiscriminator is set multiple times"); LocalDiscriminator = index; } ValueDecl *ValueDecl::getOverriddenDecl() const { auto overridden = getOverriddenDecls(); if (overridden.empty()) return nullptr; // FIXME: Arbitrarily pick the first overridden declaration. return overridden.front(); } ValueDecl *ValueDecl::getOverriddenDeclOrSuperDeinit() const { if (auto overridden = getOverriddenDecl()) { return overridden; } if (auto dtor = dyn_cast(this)) { return dtor->getSuperDeinit(); } return nullptr; } bool ValueDecl::overriddenDeclsComputed() const { return LazySemanticInfo.hasOverriddenComputed; } bool swift::conflicting(const OverloadSignature& sig1, const OverloadSignature& sig2, bool skipProtocolExtensionCheck) { // A member of a protocol extension never conflicts with a member of a // protocol. if (!skipProtocolExtensionCheck && sig1.InProtocolExtension != sig2.InProtocolExtension) return false; // If the base names are different, they can't conflict. if (sig1.Name.getBaseName() != sig2.Name.getBaseName()) return false; // If one is an operator and the other is not, they can't conflict. if (sig1.UnaryOperator != sig2.UnaryOperator) return false; // If one is an instance and the other is not, they can't conflict. if (sig1.IsInstanceMember != sig2.IsInstanceMember) return false; // For distributed decls, check there's no async/no-async overloads, // since those are more fragile in distribution than we'd want distributed calls to be. // // A remote call is always 'async throws', and we can always record // an async throws "accessor" (see AccessibleFunction.cpp) as such. // This means, if we allowed async/no-async overloads of functions, // we'd have to store the precise "it was not throwing" information, // but we'll _never_ make use of such because all remote calls are // necessarily going to async to the actor in the recipient process, // and for the remote caller, they are always as-if-async. // // By banning such overloads, which may be useful in local APIs, // but too fragile in distributed APIs, we allow a remote 'v2' version // of an implementation to add or remove `async` to their implementation // without breaking calls which were made on previous 'v1' versions of // the same interface; Callers are never broken this way, and rollouts // are simpler. // // The restriction on overloads is not a problem for distributed calls, // as we don't have a vast swab of APIs which must compatibly get async // versions, as that is what the async overloading aimed to address. // // Note also, that overloading on throws is already illegal anyway. if (!sig1.IsDistributed && !sig2.IsDistributed) { // For non-distributed functions, // if one is an async function and the other is not, they don't conflict. if (sig1.IsAsyncFunction != sig2.IsAsyncFunction) return false; } // else, if any of the methods was distributed, continue checking // If one is a macro and the other is not, they can't conflict. if (sig1.IsMacro != sig2.IsMacro) return false; // If one is a compound name and the other is not, they do not conflict // if one is a property and the other is a non-nullary function. if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) { return !((sig1.IsVariable && !sig2.Name.getArgumentNames().empty()) || (sig2.IsVariable && !sig1.Name.getArgumentNames().empty())); } // Note that we intentionally ignore the HasOpaqueReturnType bit here. // For declarations that can't be overloaded by type, we want them to be // considered conflicting independent of their type. return sig1.Name == sig2.Name; } bool swift::conflicting(ASTContext &ctx, const OverloadSignature& sig1, CanType sig1Type, const OverloadSignature& sig2, CanType sig2Type, bool *wouldConflictInSwift5, bool skipProtocolExtensionCheck) { // If the signatures don't conflict to begin with, we're done. if (!conflicting(sig1, sig2, skipProtocolExtensionCheck)) return false; // Functions and enum elements do not conflict with each other if their types // are different. if (((sig1.IsFunction && sig2.IsEnumElement) || (sig1.IsEnumElement && sig2.IsFunction)) && sig1Type != sig2Type) { return false; } // Nominal types and enum elements always conflict with each other. if ((sig1.IsNominal && sig2.IsEnumElement) || (sig1.IsEnumElement && sig2.IsNominal)) { return true; } // Typealiases and enum elements always conflict with each other. if ((sig1.IsTypeAlias && sig2.IsEnumElement) || (sig1.IsEnumElement && sig2.IsTypeAlias)) { return true; } // Enum elements always conflict with each other. At this point, they // have the same base name but different types. if (sig1.IsEnumElement && sig2.IsEnumElement) { return true; } // Functions always conflict with non-functions with the same signature. // In practice, this only applies for zero argument functions. if (sig1.IsFunction != sig2.IsFunction) return true; // Variables always conflict with non-variables with the same signature. // (e.g variables with zero argument functions, variables with type // declarations) if (sig1.IsVariable != sig2.IsVariable) { // Prior to Swift 5, we permitted redeclarations of variables as different // declarations if the variable was declared in an extension of a generic // type. Make sure we maintain this behaviour in versions < 5. if (!ctx.isSwiftVersionAtLeast(5)) { if ((sig1.IsVariable && sig1.InExtensionOfGenericType) || (sig2.IsVariable && sig2.InExtensionOfGenericType)) { if (wouldConflictInSwift5) *wouldConflictInSwift5 = true; return false; } } return true; } // Otherwise, the declarations conflict if the overload types are the same. if (sig1.HasOpaqueReturnType != sig2.HasOpaqueReturnType) return false; if (sig1Type != sig2Type) return false; // The Swift 5 overload types are the same, but similar to the above, prior to // Swift 5, a variable not in an extension of a generic type got a null // overload type instead of a function type as it does now, so we really // follow that behaviour and warn if there's going to be a conflict in future. if (!ctx.isSwiftVersionAtLeast(5)) { auto swift4Sig1Type = sig1.IsVariable && !sig1.InExtensionOfGenericType ? CanType() : sig1Type; auto swift4Sig2Type = sig1.IsVariable && !sig2.InExtensionOfGenericType ? CanType() : sig1Type; if (swift4Sig1Type != swift4Sig2Type) { // Old was different to the new behaviour! if (wouldConflictInSwift5) *wouldConflictInSwift5 = true; return false; } } return true; } static Type mapSignatureFunctionType(ASTContext &ctx, Type type, bool topLevelFunction, bool isMethod, bool isInitializer, unsigned curryLevels); /// Map a type within the signature of a declaration. static Type mapSignatureType(ASTContext &ctx, Type type) { return type.transformRec([&](Type type) -> std::optional { if (type->is()) { return mapSignatureFunctionType(ctx, type, false, false, false, 1); } return std::nullopt; }); } /// Map a signature type for a parameter. static Type mapSignatureParamType(ASTContext &ctx, Type type) { return mapSignatureType(ctx, type); } /// Map an ExtInfo for a function type. /// /// When checking if two signatures should be equivalent for overloading, /// we may need to compare the extended information. /// /// In the type of the function declaration, none of the extended information /// is relevant. We cannot overload purely on 'throws' or the calling /// convention of the declaration itself. /// /// For function parameter types, we do want to be able to overload on /// 'throws', since that is part of the mangled symbol name, but not /// @noescape. static AnyFunctionType::ExtInfo mapSignatureExtInfo(AnyFunctionType::ExtInfo info, bool topLevelFunction) { if (topLevelFunction) return AnyFunctionType::ExtInfo(); return AnyFunctionType::ExtInfoBuilder() .withRepresentation(info.getRepresentation()) .withSendable(info.isSendable()) .withAsync(info.isAsync()) .withThrows(info.isThrowing(), info.getThrownError()) .withClangFunctionType(info.getClangTypeInfo().getType()) .build(); } /// Map a function's type to the type used for computing signatures, /// which involves stripping some attributes, stripping default arguments, /// transforming implicitly unwrapped optionals into strict optionals, /// stripping 'inout' on the 'self' parameter etc. static Type mapSignatureFunctionType(ASTContext &ctx, Type type, bool topLevelFunction, bool isMethod, bool isInitializer, unsigned curryLevels) { if (type->hasError()) { return type; } if (curryLevels == 0) { // In an initializer, ignore optionality. if (isInitializer) { if (auto objectType = type->getOptionalObjectType()) { type = objectType; } } // Functions and subscripts cannot overload differing only in opaque return // types. Replace the opaque type with `Any`. if (type->is()) { type = ctx.getAnyExistentialType(); } return mapSignatureParamType(ctx, type); } auto funcTy = type->castTo(); SmallVector newParams; for (const auto ¶m : funcTy->getParams()) { auto newParamType = mapSignatureParamType(ctx, param.getPlainType()); // Don't allow overloading by @_nonEphemeral or isolated. auto newFlags = param.getParameterFlags() .withNonEphemeral(false) .withIsolated(false); // For the 'self' of a method, strip off 'inout'. if (isMethod) { newFlags = newFlags.withInOut(false); } AnyFunctionType::Param newParam(newParamType, param.getLabel(), newFlags, param.getInternalLabel()); newParams.push_back(newParam); } // Map the result type. auto resultTy = mapSignatureFunctionType( ctx, funcTy->getResult(), topLevelFunction, false, isInitializer, curryLevels - 1); // Map various attributes differently depending on if we're looking at // the declaration, or a function parameter type. AnyFunctionType::ExtInfo info = mapSignatureExtInfo( funcTy->getExtInfo(), topLevelFunction); // Rebuild the resulting function type. if (auto genericFuncTy = dyn_cast(funcTy)) return GenericFunctionType::get(genericFuncTy->getGenericSignature(), newParams, resultTy, info); return FunctionType::get(newParams, resultTy, info); } OverloadSignature ValueDecl::getOverloadSignature() const { OverloadSignature signature; signature.Name = getName(); signature.InProtocolExtension = static_cast(getDeclContext()->getExtendedProtocolDecl()); signature.IsInstanceMember = isInstanceMember(); signature.IsVariable = isa(this); signature.IsEnumElement = isa(this); signature.IsNominal = isa(this); signature.IsTypeAlias = isa(this); signature.IsMacro = isa(this); signature.HasOpaqueReturnType = !signature.IsVariable && (bool)getOpaqueResultTypeDecl(); // Unary operators also include prefix/postfix. if (auto func = dyn_cast(this)) { if (func->isUnaryOperator()) { signature.UnaryOperator = func->getAttrs().getUnaryOperatorKind(); } } // Functions include async/not-async. if (auto func = dyn_cast(this)) { signature.IsFunction = true; if (func->hasAsync()) signature.IsAsyncFunction = true; if (func->isDistributed()) signature.IsDistributed = true; } if (auto *extension = dyn_cast(getDeclContext())) if (extension->isGeneric()) signature.InExtensionOfGenericType = true; return signature; } CanType ValueDecl::getOverloadSignatureType() const { if (auto *afd = dyn_cast(this)) { bool isMethod = afd->hasImplicitSelfDecl(); return mapSignatureFunctionType(getASTContext(), getInterfaceType(), /*topLevelFunction=*/true, isMethod, /*isInitializer=*/isa(afd), getNumCurryLevels()) ->getMinimalCanonicalType(); } if (isa(this)) { // First, get the default overload signature type for the decl. For vars, // this is the empty tuple type, as variables cannot be overloaded directly // by type. For subscripts, it's their interface type. CanType defaultSignatureType; if (isa(this)) { defaultSignatureType = TupleType::getEmpty(getASTContext()); } else { defaultSignatureType = mapSignatureFunctionType(getASTContext(), getInterfaceType(), /*topLevelFunction=*/true, /*isMethod=*/false, /*isInitializer=*/false, getNumCurryLevels()) ->getMinimalCanonicalType(); } // We want to curry the default signature type with the 'self' type of the // given context (if any) in order to ensure the overload signature type // is unique across different contexts, such as between a protocol extension // and struct decl. return defaultSignatureType->addCurriedSelfType(getDeclContext()) ->getCanonicalType(); } if (isa(this) || isa(this)) { auto mappedType = mapSignatureFunctionType( getASTContext(), getInterfaceType(), /*topLevelFunction=*/false, /*isMethod=*/false, /*isInitializer=*/false, getNumCurryLevels()); return mappedType->getMinimalCanonicalType(); } // Note: If you add more cases to this function, you should update the // implementation of the swift::conflicting overload that deals with // overload types, in order to account for cases where the overload types // don't match, but the decls differ and therefore always conflict. assert(isa(this)); return CanType(); } llvm::TinyPtrVector ValueDecl::getOverriddenDecls() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, OverriddenDeclsRequest{const_cast(this)}, {}); } void ValueDecl::setOverriddenDecls(ArrayRef overridden) { llvm::TinyPtrVector overriddenVec(overridden); OverriddenDeclsRequest request{const_cast(this)}; request.cacheResult(overriddenVec); } // To-Do: Replce calls to getOpaqueResultTypeRepr with getResultTypeRepr() TypeRepr *ValueDecl::getResultTypeRepr() const { TypeRepr *returnRepr = nullptr; if (auto *VD = dyn_cast(this)) { if (auto *P = VD->getParentPattern()) { while (auto *PP = dyn_cast(P)) P = PP->getSubPattern(); if (auto *TP = dyn_cast(P)) { P = P->getSemanticsProvidingPattern(); if (auto *NP = dyn_cast(P)) { assert(NP->getDecl() == VD); (void)NP; returnRepr = TP->getTypeRepr(); } } } else { returnRepr = VD->getTypeReprOrParentPatternTypeRepr(); } } else if (auto *FD = dyn_cast(this)) { returnRepr = FD->getResultTypeRepr(); } else if (auto *SD = dyn_cast(this)) { returnRepr = SD->getElementTypeRepr(); } else if (auto *MD = dyn_cast(this)) { returnRepr = MD->resultType.getTypeRepr(); } else if (auto *CD = dyn_cast(this)) { returnRepr = CD->getResultTypeRepr(); } return returnRepr; } TypeRepr *ValueDecl::getOpaqueResultTypeRepr() const { // FIXME: Macros don't allow opaque result types yet. if (isa(this)) return nullptr; auto *returnRepr = this->getResultTypeRepr(); auto *dc = getDeclContext(); auto &ctx = dc->getASTContext(); if (returnRepr && returnRepr->hasOpaque()) { return returnRepr; } else if (returnRepr && ctx.LangOpts.hasFeature(Feature::ImplicitSome)) { auto opaqueReprs = collectOpaqueTypeReprs(returnRepr, getASTContext(), getDeclContext()); return opaqueReprs.empty() ? nullptr : returnRepr; } else { return nullptr; } } OpaqueTypeDecl *ValueDecl::getOpaqueResultTypeDecl() const { if (getOpaqueResultTypeRepr() == nullptr) { if (!isa(this) && !isa(this) && !isa(this)) return nullptr; auto file = cast(getDeclContext()->getModuleScopeContext()); // Don't look up when the decl is from source, otherwise a cycle will happen. if (file->getKind() == FileUnitKind::SerializedAST) { Mangle::ASTMangler mangler; auto name = mangler.mangleOpaqueTypeDecl(this); return file->lookupOpaqueResultType(name); } return nullptr; } return evaluateOrDefault(getASTContext().evaluator, OpaqueResultTypeRequest{const_cast(this)}, nullptr); } bool ValueDecl::isObjC() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsObjCRequest{const_cast(this)}, getAttrs().hasAttribute()); } void ValueDecl::setIsObjC(bool value) { assert(!LazySemanticInfo.isObjCComputed || LazySemanticInfo.isObjC == value); if (LazySemanticInfo.isObjCComputed) { assert(LazySemanticInfo.isObjC == value); return; } LazySemanticInfo.isObjCComputed = true; LazySemanticInfo.isObjC = value; } Identifier ExtensionDecl::getObjCCategoryName() const { // If there's an @objc attribute, it's authoritative. (ClangImporter // attaches one automatically.) if (auto objcAttr = getAttrs().getAttribute(/*AllowInvalid*/true)) { if (objcAttr->hasName() && objcAttr->getName()->getNumArgs() == 0) return objcAttr->getName()->getSimpleName(); return Identifier(); } // Not a category, evidently. return Identifier(); } bool ValueDecl::isSemanticallyFinal() const { // Actor types are semantically final. if (auto classDecl = dyn_cast(this)) { if (classDecl->isAnyActor()) return true; } // As are methods/accessors of actor types. if (!isa(this)) { if (auto classDecl = getDeclContext()->getSelfClassDecl()) { if (classDecl->isAnyActor()) return true; } } // For everything else, the same as 'final'. return isFinal(); } bool ValueDecl::isFinal() const { return evaluateOrDefault(getASTContext().evaluator, IsFinalRequest { const_cast(this) }, getAttrs().hasAttribute()); } bool ValueDecl::isDynamic() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsDynamicRequest{const_cast(this)}, getAttrs().hasAttribute()); } bool ValueDecl::isObjCDynamicInGenericClass() const { if (!isObjCDynamic()) return false; auto *DC = this->getDeclContext(); auto *classDecl = DC->getSelfClassDecl(); if (!classDecl) return false; return classDecl->isGenericContext() && !classDecl->isTypeErasedGenericClass(); } bool ValueDecl::shouldUseObjCMethodReplacement() const { if (isNativeDynamic()) return false; if (getModuleContext()->isImplicitDynamicEnabled() && isObjCDynamicInGenericClass()) return false; return isObjCDynamic(); } bool ValueDecl::shouldUseNativeMethodReplacement() const { if (isNativeDynamic()) return true; if (!isObjCDynamicInGenericClass()) return false; auto *replacedDecl = getDynamicallyReplacedDecl(); if (replacedDecl) return false; return getModuleContext()->isImplicitDynamicEnabled(); } bool ValueDecl::isNativeMethodReplacement() const { // Is this a @_dynamicReplacement(for:) that use the native dynamic function // replacement mechanism. auto *replacedDecl = getDynamicallyReplacedDecl(); if (!replacedDecl) return false; if (isNativeDynamic()) return true; if (replacedDecl->isObjCDynamicInGenericClass()) return replacedDecl->getModuleContext()->isImplicitDynamicEnabled(); return false; } void ValueDecl::setIsDynamic(bool value) { assert(!LazySemanticInfo.isDynamicComputed || LazySemanticInfo.isDynamic == value); if (LazySemanticInfo.isDynamicComputed) { assert(LazySemanticInfo.isDynamic == value); return; } LazySemanticInfo.isDynamicComputed = true; LazySemanticInfo.isDynamic = value; } ValueDecl *ValueDecl::getDynamicallyReplacedDecl() const { return evaluateOrDefault(getASTContext().evaluator, DynamicallyReplacedDeclRequest{ const_cast(this)}, nullptr); } bool ValueDecl::canBeAccessedByDynamicLookup() const { if (!hasName()) return false; auto *dc = getDeclContext(); if (!dc->mayContainMembersAccessedByDynamicLookup()) return false; // Dynamic lookup can find functions, variables, and subscripts. if (!isa(this) && !isa(this) && !isa(this)) return false; return true; } bool ValueDecl::isImplicitlyUnwrappedOptional() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsImplicitlyUnwrappedOptionalRequest{const_cast(this)}, false); } bool ValueDecl::isLocalCapture() const { auto *dc = getDeclContext(); if (auto *fd = dyn_cast(this)) if (isa(dc)) return fd->hasTopLevelLocalContextCaptures(); return dc->isLocalContext(); } ArrayRef ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const { // Dig out the nominal type. NominalTypeDecl *NTD = getDeclContext()->getSelfNominalTypeDecl(); if (!NTD || isa(NTD)) return {}; return NTD->getSatisfiedProtocolRequirementsForMember(this, Sorted); } std::optional> ValueDecl::findImport(const DeclContext *fromDC) const { // If the type is from the current module, there's no import. auto module = getModuleContextForNameLookup(); if (module == fromDC->getParentModule()) return std::nullopt; auto fromSourceFile = fromDC->getParentSourceFile(); if (!fromSourceFile) return std::nullopt; return fromSourceFile->findImport(module); } bool ValueDecl::isProtocolRequirement() const { assert(isa(getDeclContext())); if (isa(this) || isa(this) || isa(this)) return false; return true; } bool ValueDecl::hasInterfaceType() const { return !TypeAndAccess.getPointer().isNull(); } static bool isComputingInterfaceType(const ValueDecl *VD) { return VD->getASTContext().evaluator.hasActiveRequest( InterfaceTypeRequest{const_cast(VD)}); } bool ValueDecl::isRecursiveValidation() const { if (isComputingInterfaceType(this) && !hasInterfaceType()) return true; if (auto *vd = dyn_cast(this)) if (auto *pbd = vd->getParentPatternBinding()) if (pbd->isComputingPatternBindingEntry(vd)) return true; auto *dc = getDeclContext(); while (isa(dc)) dc = dc->getParent(); if (auto *ext = dyn_cast(dc)) { if (ext->isComputingGenericSignature()) return true; } return false; } Type ValueDecl::getInterfaceType() const { auto &ctx = getASTContext(); return ctx.evaluator(InterfaceTypeRequest{const_cast(this)}, [&ctx]() { return ErrorType::get(ctx); }); } void ValueDecl::setInterfaceType(Type type) { assert(!type.isNull() && "Resetting the interface type to null is forbidden"); getASTContext().evaluator.cacheOutput(InterfaceTypeRequest{this}, std::move(type)); } StringRef ValueDecl::getCDeclName() const { // Treat imported C functions as implicitly @_cdecl. if (auto clangDecl = dyn_cast_or_null(getClangDecl())) { if (clangDecl->getLanguageLinkage() == clang::CLanguageLinkage && clangDecl->getIdentifier()) return clangDecl->getName(); } // Handle explicit cdecl attributes. if (auto cdeclAttr = getAttrs().getAttribute()) { return cdeclAttr->Name; } return ""; } std::optional ValueDecl::getObjCRuntimeName(bool skipIsObjCResolution) const { if (auto func = dyn_cast(this)) return func->getObjCSelector(DeclName(), skipIsObjCResolution); ASTContext &ctx = getASTContext(); auto makeSelector = [&](Identifier name) -> ObjCSelector { return ObjCSelector(ctx, 0, { name }); }; if (auto classDecl = dyn_cast(this)) { SmallString<32> scratch; return makeSelector( ctx.getIdentifier(classDecl->getObjCRuntimeName(scratch))); } if (auto protocol = dyn_cast(this)) { SmallString<32> scratch; return makeSelector( ctx.getIdentifier(protocol->getObjCRuntimeName(scratch))); } if (auto var = dyn_cast(this)) return makeSelector(var->getObjCPropertyName()); return std::nullopt; } bool ValueDecl::canInferObjCFromRequirement(ValueDecl *requirement) { // Only makes sense for a requirement of an @objc protocol. auto proto = cast(requirement->getDeclContext()); if (!proto->isObjC()) return false; // Only makes sense when this declaration is within a nominal type // or extension thereof. auto nominal = getDeclContext()->getSelfNominalTypeDecl(); if (!nominal) return false; // If there is already an @objc attribute with an explicit name, we // can't infer a name (it's already there). if (auto objcAttr = getAttrs().getAttribute()) { if (objcAttr->hasName() && !objcAttr->isNameImplicit()) return false; } // If the nominal type doesn't conform to the protocol at all, we // cannot infer @objc no matter what we do. SmallVector conformances; if (!nominal->lookupConformance(proto, conformances)) return false; // If any of the conformances is attributed to the context in which // this declaration resides, we can infer @objc or the Objective-C // name. auto dc = getDeclContext(); for (auto conformance : conformances) { if (conformance->getDeclContext() == dc) return true; } // Nothing to infer from. return false; } SourceLoc Decl::getAttributeInsertionLoc(bool forModifier) const { // Some decls have a parent/child split where the introducer keyword is on the // parent, but the attributes are on the children. If this is a child in such // a pair, `introDecl` will be changed to point to the parent. (The parent // decl should delegate to one of its children.) const Decl *introDecl = this; switch (getKind()) { case DeclKind::Module: case DeclKind::TopLevelCode: case DeclKind::PoundDiagnostic: case DeclKind::Missing: case DeclKind::MissingMember: case DeclKind::MacroExpansion: case DeclKind::BuiltinTuple: // These don't take attributes. return SourceLoc(); case DeclKind::EnumCase: // An ECD's attributes are attached to its elements. if (auto elem = cast(this)->getFirstElement()) return elem->getAttributeInsertionLoc(forModifier); break; case DeclKind::EnumElement: // An EED's introducer keyword is on its parent case. if (auto parent = cast(this)->getParentCase()) introDecl = parent; break; case DeclKind::PatternBinding: { // A PBD's attributes are attached to the vars in its patterns. auto pbd = cast(this); for (unsigned i = 0; i < pbd->getNumPatternEntries(); i++) { if (auto var = pbd->getAnchoringVarDecl(i)) { return var->getAttributeInsertionLoc(forModifier); } } break; } case DeclKind::Var: case DeclKind::Param: // A VarDecl's introducer keyword, if it has one, is on its pattern binding. if (auto pbd = cast(this)->getParentPatternBinding()) introDecl = pbd; break; case DeclKind::Enum: case DeclKind::Struct: case DeclKind::Class: case DeclKind::Protocol: case DeclKind::OpaqueType: case DeclKind::TypeAlias: case DeclKind::GenericTypeParam: case DeclKind::AssociatedType: case DeclKind::Subscript: case DeclKind::Constructor: case DeclKind::Destructor: case DeclKind::Func: case DeclKind::Accessor: case DeclKind::Macro: case DeclKind::Extension: case DeclKind::Import: case DeclKind::PrecedenceGroup: case DeclKind::InfixOperator: case DeclKind::PrefixOperator: case DeclKind::PostfixOperator: // Both the introducer keyword and the attributes are on `this`. break; } if (isImplicit()) return SourceLoc(); SourceLoc resultLoc = getAttrs().getStartLoc(forModifier); return resultLoc.isValid() ? resultLoc : introDecl->getStartLoc(); } /// Returns true if \p VD needs to be treated as publicly-accessible /// at the SIL, LLVM, and machine levels due to being @usableFromInline. bool ValueDecl::isUsableFromInline() const { assert(getFormalAccess() < AccessLevel::Public); if (getAttrs().hasAttribute() || getAttrs().hasAttribute() || getAttrs().hasAttribute()) return true; if (auto *accessor = dyn_cast(this)) { auto *storage = accessor->getStorage(); if (storage->getAttrs().hasAttribute() || storage->getAttrs().hasAttribute() || storage->getAttrs().hasAttribute()) return true; } if (auto *opaqueType = dyn_cast(this)) { if (auto *namingDecl = opaqueType->getNamingDecl()) { if (namingDecl->getAttrs().hasAttribute() || namingDecl->getAttrs().hasAttribute() || namingDecl->getAttrs().hasAttribute()) return true; } } if (auto *EED = dyn_cast(this)) if (EED->getParentEnum()->getAttrs().hasAttribute()) return true; if (auto *containingProto = dyn_cast(getDeclContext())) { if (containingProto->getAttrs().hasAttribute()) return true; } if (auto *DD = dyn_cast(this)) if (auto *CD = dyn_cast(DD->getDeclContext())) if (CD->getAttrs().hasAttribute()) return true; return false; } bool ValueDecl::isInterfacePackageEffectivelyPublic() const { // A package decl with @usableFromInline (or other inlinable // attributes) is essentially public, and can be printed in // public (or private) interface file without package-name; // it can be referenced by another module (without package-name) // importing such interface module. auto isCandidate = getFormalAccess() == AccessLevel::Package && isUsableFromInline() && getModuleContext()->getPackageName().empty(); if (!isCandidate) return false; // Treat the decl as public (1) if it's contained in an interface // file, e.g. when running -typecheck-module-from-interface or // -compile-module-from-interface. isCandidate = false; if (auto srcFile = getDeclContext()->getParentSourceFile()) { isCandidate = srcFile->Kind == SourceFileKind::Interface; } // Or (2) if the decl being referenced in a client file is defined // in an interface module. return isCandidate || getModuleContext()->isBuiltFromInterface(); } bool ValueDecl::shouldHideFromEditor() const { // Hide private stdlib declarations. if (isPrivateSystemDecl(/*treatNonBuiltinProtocolsAsPublic*/ false) || // ShowInInterfaceAttr is for decls to show in interface as exception but // they are not intended to be used directly. getAttrs().hasAttribute()) return true; if (AvailableAttr::isUnavailable(this)) return true; // Hide 'swift_private' clang decls. They are imported with '__' prefix. if (auto *ClangD = getClangDecl()) { bool bypassSwiftPrivate = false; if (auto *AFD = dyn_cast(this)) { if (AFD->getForeignAsyncConvention().has_value()) { // For imported 'async' declarations, visibility can be controlled by // 'swift_async(...)' attribute. if (auto *asyncAttr = ClangD->getAttr()) { bypassSwiftPrivate = true; switch (asyncAttr->getKind()) { case clang::SwiftAsyncAttr::None: // Should be unreachable. return true; case clang::SwiftAsyncAttr::SwiftPrivate: // Hide 'swift_async(swift_private, ...)'. return true; case clang::SwiftAsyncAttr::NotSwiftPrivate: break; } } else if (ClangD->getAttr()) { // Manually specifying the name bypasses 'swift_private' attr. bypassSwiftPrivate = true; } } } if (!bypassSwiftPrivate && ClangD->hasAttr()) return true; } if (!isUserAccessible()) return true; // Hide editor placeholders. if (getBaseName().isEditorPlaceholder()) return true; // '$__' names are reserved by compiler internal. if (!getBaseName().isSpecial() && getBaseIdentifier().str().starts_with("$__")) return true; // Macro unique names are only intended to be used inside the expanded code. if (MacroDecl::isUniqueMacroName(getBaseName())) return true; return false; } /// Return maximally open access level which could be associated with the /// given declaration accounting for @testable importers. static AccessLevel getMaximallyOpenAccessFor(const ValueDecl *decl) { // Non-final classes are considered open to @testable importers. if (auto cls = dyn_cast(decl)) { if (!cls->isSemanticallyFinal()) return AccessLevel::Open; // Non-final overridable class members are considered open to // @testable importers. } else if (decl->isSyntacticallyOverridable()) { if (!cast(decl)->isSemanticallyFinal()) return AccessLevel::Open; } // Everything else is considered public. return AccessLevel::Public; } /// Adjust \p access based on whether \p VD is \@usableFromInline, has been /// testably imported from \p useDC or \p VD is an imported SPI. /// /// \p access isn't always just `VD->getFormalAccess()` because this adjustment /// may be for a write, in which case the setter's access might be used instead. static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, AccessLevel access, const DeclContext *useDC, bool treatUsableFromInlineAsPublic) { // If access control is disabled in the current context, adjust // access level of the current declaration to be as open as possible. if (useDC && VD->getASTContext().isAccessControlDisabled()) return getMaximallyOpenAccessFor(VD); if (VD->isInterfacePackageEffectivelyPublic()) return AccessLevel::Public; if (treatUsableFromInlineAsPublic && access < AccessLevel::Public && VD->isUsableFromInline()) { return AccessLevel::Public; } if (useDC) { // If the use site decl context is PackageUnit, just return // the access level that's passed in if (auto usePkg = useDC->getPackageContext()) return access; // Check whether we need to modify the access level based on // @testable/@_private import attributes. auto *useSF = dyn_cast(useDC->getModuleScopeContext()); if (!useSF) return access; if (useSF->hasTestableOrPrivateImport(access, VD)) return getMaximallyOpenAccessFor(VD); } return access; } /// Convenience overload that uses `VD->getFormalAccess()` as the access to /// adjust. static AccessLevel getAdjustedFormalAccess(const ValueDecl *VD, const DeclContext *useDC, bool treatUsableFromInlineAsPublic) { return getAdjustedFormalAccess(VD, VD->getFormalAccess(), useDC, treatUsableFromInlineAsPublic); } AccessLevel ValueDecl::getEffectiveAccess() const { auto effectiveAccess = getAdjustedFormalAccess(this, /*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); // Handle @testable/@_private(sourceFile:) switch (effectiveAccess) { case AccessLevel::Open: case AccessLevel::Package: case AccessLevel::Public: case AccessLevel::Internal: if (getModuleContext()->isTestingEnabled() || getModuleContext()->arePrivateImportsEnabled()) effectiveAccess = getMaximallyOpenAccessFor(this); break; case AccessLevel::FilePrivate: if (getModuleContext()->arePrivateImportsEnabled()) effectiveAccess = getMaximallyOpenAccessFor(this); break; case AccessLevel::Private: effectiveAccess = AccessLevel::FilePrivate; if (getModuleContext()->arePrivateImportsEnabled()) effectiveAccess = getMaximallyOpenAccessFor(this); break; } auto restrictToEnclosing = [this](AccessLevel effectiveAccess, AccessLevel enclosingAccess) -> AccessLevel{ if (effectiveAccess == AccessLevel::Open && enclosingAccess == AccessLevel::Public && isa(this)) { // Special case: an open class may be contained in a public // class/struct/enum. Leave effectiveAccess as is. return effectiveAccess; } return std::min(effectiveAccess, enclosingAccess); }; if (auto enclosingNominal = dyn_cast(getDeclContext())) { effectiveAccess = restrictToEnclosing(effectiveAccess, enclosingNominal->getEffectiveAccess()); } else if (auto enclosingExt = dyn_cast(getDeclContext())) { // Just check the base type. If it's a constrained extension, Sema should // have already enforced access more strictly. if (auto nominal = enclosingExt->getExtendedNominal()) { effectiveAccess = restrictToEnclosing(effectiveAccess, nominal->getEffectiveAccess()); } } else if (getDeclContext()->isLocalContext()) { effectiveAccess = AccessLevel::FilePrivate; } return effectiveAccess; } AccessLevel ValueDecl::getFormalAccess() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, AccessLevelRequest{const_cast(this)}, AccessLevel::Private); } bool ValueDecl::hasOpenAccess(const DeclContext *useDC) const { AccessLevel access = getAdjustedFormalAccess(this, useDC, /*treatUsableFromInlineAsPublic*/false); return access == AccessLevel::Open; } bool ValueDecl::bypassResilienceInPackage(ModuleDecl *accessingModule) const { // If the defining module is built with package-cmo, bypass // resilient access from the use site that belongs to a module // in the same package. auto declModule = getModuleContext(); return declModule->inSamePackage(accessingModule) && declModule->isResilient() && declModule->allowNonResilientAccess() && declModule->serializePackageEnabled(); } /// Given the formal access level for using \p VD, compute the scope where /// \p VD may be accessed, taking \@usableFromInline, \@testable imports, /// \@_spi imports, and enclosing access levels into account. /// /// \p access isn't always just `VD->getFormalAccess()` because this adjustment /// may be for a write, in which case the setter's access might be used instead. static AccessScope getAccessScopeForFormalAccess(const ValueDecl *VD, AccessLevel formalAccess, const DeclContext *useDC, bool treatUsableFromInlineAsPublic) { AccessLevel access = getAdjustedFormalAccess(VD, formalAccess, useDC, treatUsableFromInlineAsPublic); const DeclContext *resultDC = VD->getDeclContext(); while (!resultDC->isModuleScopeContext()) { if (isa(resultDC)) { return AccessScope(resultDC->getModuleScopeContext(), access == AccessLevel::Private); } if (resultDC->isLocalContext() || access == AccessLevel::Private) return AccessScope(resultDC, /*private*/ true); if (auto enclosingNominal = dyn_cast(resultDC)) { auto enclosingAccess = getAdjustedFormalAccess(enclosingNominal, useDC, treatUsableFromInlineAsPublic); access = std::min(access, enclosingAccess); } else if (auto enclosingExt = dyn_cast(resultDC)) { // Just check the base type. If it's a constrained extension, Sema should // have already enforced access more strictly. if (auto nominal = enclosingExt->getExtendedNominal()) { if (nominal->getParentModule() == enclosingExt->getParentModule()) { auto nominalAccess = getAdjustedFormalAccess(nominal, useDC, treatUsableFromInlineAsPublic); access = std::min(access, nominalAccess); } } } else { llvm_unreachable("unknown DeclContext kind"); } resultDC = resultDC->getParent(); } auto localImportRestriction = VD->getImportAccessFrom(useDC); if (localImportRestriction.has_value()) { AccessLevel importAccessLevel = localImportRestriction.value().accessLevel; if (access > importAccessLevel) { access = std::min(access, importAccessLevel); resultDC = useDC->getParentSourceFile(); } } switch (access) { case AccessLevel::Private: case AccessLevel::FilePrivate: assert(resultDC->isModuleScopeContext()); return AccessScope(resultDC, access == AccessLevel::Private); case AccessLevel::Internal: return AccessScope(resultDC->getParentModule()); case AccessLevel::Package: { auto pkg = resultDC->getPackageContext(/*lookupIfNotCurrent*/ true); if (!pkg) { if (VD->isInterfacePackageEffectivelyPublic()) return AccessScope::getPublic(); // If reached here, should be treated as internal. return AccessScope(resultDC->getParentModule()); } else { return AccessScope(pkg); } } case AccessLevel::Public: case AccessLevel::Open: return AccessScope::getPublic(); } llvm_unreachable("unknown access level"); } AccessScope ValueDecl::getFormalAccessScope(const DeclContext *useDC, bool treatUsableFromInlineAsPublic) const { return getAccessScopeForFormalAccess(this, getFormalAccess(), useDC, treatUsableFromInlineAsPublic); } /// Checks if \p VD may be used from \p useDC, taking \@testable imports into /// account. /// /// Whenever the enclosing context of \p VD is usable from \p useDC, this /// should compute the same result as checkAccess, below, but more slowly. /// /// Here's an example while typechecking a file with the following code. /// /// ``` /// import OtherModule /// /// // `Foo` is a `public` struct defined in `OtherModule` /// public func myFunc(_ arg: OtherModule.Foo) {} /// ``` /// /// The use site of `Foo`is a function `myFunc`, and its DeclContext (useDC) /// is FileUnit. The call \c getAccessScopeForFormalAccess inside this function /// to get the access scope of`Foo` returns a public scope based on its `public` /// access level, which is a wrapper around a nullptr DeclContext. Note that the /// useDC is still non-null (FileUnit) even though the use site itself also has /// a `public` acess level. /// /// The `isChildOf` call compares the DeclContext hierarchy of the use site /// (useDC) and the decl (VD) site, and returns true in this case, since /// FileUnit is a child of nullptr based on the DeclContext hierarchy. The /// hierarchy is created when subclasses of DeclContext such as FileUnit or /// ModuleDecl are constructed. For example, a top ClassDecl ctor takes FileUnit /// as its parent DeclContext and FileUnit ctor takes ModuleDecl as its parent /// DeclContext. There's an exception, however, for the case of PackageUnit. /// \see PackageUnit for details on how the hierachy between that and ModuleDecl /// is created. /// \see DeclContext::ASTHierarchy /// \see AccessScope::getAccessScopeForFormalAccess /// \see ValueDecl::isAccessibleFrom for a description of \p forConformance. static bool checkAccessUsingAccessScopes(const DeclContext *useDC, const ValueDecl *VD, AccessLevel access, bool includeInlineable) { if (VD->getASTContext().isAccessControlDisabled()) return true; AccessScope accessScope = getAccessScopeForFormalAccess( VD, access, useDC, /*treatUsableFromInlineAsPublic*/ includeInlineable); if (accessScope.getDeclContext() == useDC) return true; if (!AccessScope(useDC).isChildOf(accessScope)) return false; // useDC is null only when caller wants to skip non-public type checks. if (!useDC) return true; // Check SPI access if (!VD->isSPI()) return true; auto useSF = dyn_cast(useDC->getModuleScopeContext()); return !useSF || useSF->isImportedAsSPI(VD) || VD->getDeclContext()->getParentModule() == useDC->getParentModule(); } /// Checks if \p VD is an ObjC member implementation: /// /// \li It's in an \c \@_objcImplementation extension /// \li It's not explicitly \c final /// \li Its access level is not \c private or \c fileprivate static bool isObjCMemberImplementation(const ValueDecl *VD, llvm::function_ref getAccessLevel) { if (auto ED = dyn_cast(VD->getDeclContext())) if (ED->isObjCImplementation() && !isa(VD)) { auto attrDecl = isa(VD) ? cast(VD)->getStorage() : VD; return !attrDecl->isFinal() && !attrDecl->getAttrs().hasAttribute() && !attrDecl->getAttrs().hasAttribute() && getAccessLevel() >= AccessLevel::Internal; } return false; } bool ValueDecl::isObjCMemberImplementation() const { return ::isObjCMemberImplementation( this, [&]() { return this->getFormalAccess(); }); } /// Checks if \p VD may be used from \p useDC, taking \@testable and \@_spi /// imports into account. /// /// When \p access is the same as `VD->getFormalAccess()` and the enclosing /// context of \p VD is usable from \p useDC, this ought to be the same as /// getting the AccessScope for `VD` and checking if \p useDC is within it. /// However, there's a source compatibility hack around protocol extensions /// that makes it not quite the same. /// /// See ValueDecl::isAccessibleFrom for a description of \p forConformance. static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD, bool forConformance, bool includeInlineable, llvm::function_ref getAccessLevel) { // If this is an @_objcImplementation member implementation, and we aren't in // a context where we would access its storage directly, forbid access. Name // lookups will instead find and use the matching interface decl. // FIXME: Passing `true` for `isAccessOnSelf` may cause false positives. if ((VD->isObjCImplementation() || isObjCMemberImplementation(VD, getAccessLevel)) && VD->getAccessSemanticsFromContext(useDC, /*isAccessOnSelf=*/true) != AccessSemantics::DirectToStorage) return false; if (VD->getASTContext().isAccessControlDisabled()) return true; if (VD->isInterfacePackageEffectivelyPublic()) return true; auto access = getAccessLevel(); auto *sourceDC = VD->getDeclContext(); // Preserve "fast path" behavior for everything inside // protocol extensions and operators, otherwise allow access // check declarations inside inaccessible members via slower // access scope based check, which is helpful for diagnostics. if (!(sourceDC->getSelfProtocolDecl() || VD->isOperator())) return checkAccessUsingAccessScopes(useDC, VD, access, includeInlineable); if (!forConformance) { if (auto *proto = sourceDC->getSelfProtocolDecl()) { // FIXME: Swift 4.1 allowed accessing protocol extension methods that were // marked 'public' if the protocol was '@_versioned' (now // '@usableFromInline'). Which works at the ABI level, so let's keep // supporting that here by explicitly checking for it. auto protoAccess = proto->getFormalAccess(); if (access == AccessLevel::Public && (protoAccess == AccessLevel::Internal || protoAccess == AccessLevel::Package) && proto->isUsableFromInline()) { return true; } // Skip the fast path below and just compare access scopes. return checkAccessUsingAccessScopes(useDC, VD, access, includeInlineable); } } // Fast path: assume that the client context already has access to our parent // DeclContext, and only check what might be different about this declaration. if (!useDC) return access >= AccessLevel::Public; switch (access) { case AccessLevel::Private: if (useDC != sourceDC) { auto *useSF = dyn_cast(useDC->getModuleScopeContext()); if (useSF && useSF->hasTestableOrPrivateImport(access, VD)) return true; } return (useDC == sourceDC || AccessScope::allowsPrivateAccess(useDC, sourceDC)); case AccessLevel::FilePrivate: if (useDC->getModuleScopeContext() != sourceDC->getModuleScopeContext()) { auto *useSF = dyn_cast(useDC->getModuleScopeContext()); return useSF && useSF->hasTestableOrPrivateImport(access, VD); } return true; case AccessLevel::Internal: { // Invalid if the use site is > Internal. // E.g. extension containing a member of a protocol it conforms to has // `package` access level but the member is `internal` if (useDC->getContextKind() == DeclContextKind::Package) return false; const ModuleDecl *sourceModule = sourceDC->getParentModule(); const DeclContext *useFile = useDC->getModuleScopeContext(); if (useFile->getParentModule() == sourceModule) return true; auto *useSF = dyn_cast(useFile); return useSF && useSF->hasTestableOrPrivateImport(access, sourceModule); } case AccessLevel::Package: { auto srcPkg = sourceDC->getPackageContext(/*lookupIfNotCurrent*/ true); auto usePkg = useDC->getPackageContext(/*lookupIfNotCurrent*/ true); return srcPkg && usePkg && usePkg->isSamePackageAs(srcPkg); } case AccessLevel::Public: case AccessLevel::Open: return true; } llvm_unreachable("bad access level"); } bool ValueDecl::isMoreVisibleThan(ValueDecl *other) const { auto scope = getFormalAccessScope(/*UseDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); // 'other' may have come from a @testable import, so we need to upgrade it's // visibility to public here. That is not the same as whether 'other' is // being built with -enable-testing though -- we don't want to treat it // differently in that case. auto otherScope = other->getFormalAccessScope(getDeclContext(), /*treatUsableFromInlineAsPublic=*/true); if (scope.isPublic()) return !otherScope.isPublic(); else if (scope.isPackage()) return !otherScope.isPublicOrPackage(); else if (scope.isInternal()) return !otherScope.isPublic() && !otherScope.isInternal(); else return false; } bool ValueDecl::isAccessibleFrom(const DeclContext *useDC, bool forConformance, bool allowUsableFromInline) const { return checkAccess(useDC, this, forConformance, allowUsableFromInline, [&]() { return getFormalAccess(); }); } ImportAccessLevel Decl::getImportAccessFrom(const DeclContext *useDC) const { ModuleDecl *Mod = getModuleContext(); if (useDC && useDC->getParentModule() != Mod) { if (auto useSF = useDC->getParentSourceFile()) { return useSF->getImportAccessLevel(Mod); } } return std::nullopt; } bool AbstractStorageDecl::isSetterAccessibleFrom(const DeclContext *DC, bool forConformance) const { assert(isSettable(DC)); // If a stored property does not have a setter, it is still settable from the // designated initializer constructor. In this case, don't check setter // access; it is not set. if (hasStorage() && !isSettable(nullptr)) return true; if (isa(this)) return true; return checkAccess(DC, this, forConformance, /*includeInlineable*/ false, [&]() { return getSetterFormalAccess(); }); } void ValueDecl::copyFormalAccessFrom(const ValueDecl *source, bool sourceIsParentContext) { assert(!hasAccess()); AccessLevel access = source->getFormalAccess(); // To make something have the same access as a 'private' parent, it has to // be 'fileprivate' or greater. if (sourceIsParentContext && access == AccessLevel::Private) access = AccessLevel::FilePrivate; // Only certain declarations can be 'open'. if (access == AccessLevel::Open && !isSyntacticallyOverridable()) { assert(!isa(this) && "copying 'open' onto a class has complications"); access = AccessLevel::Public; } setAccess(access); // Inherit the @usableFromInline attribute. if (source->getAttrs().hasAttribute() && !getAttrs().hasAttribute() && !getAttrs().hasAttribute() && DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind::UsableFromInline, this)) { auto &ctx = getASTContext(); auto *clonedAttr = new (ctx) UsableFromInlineAttr(/*implicit=*/true); getAttrs().add(clonedAttr); } } TypeDecl::CanBeInvertible::Result NominalTypeDecl::canConformTo(InvertibleProtocolKind ip) const { auto *proto = getASTContext().getProtocol(getKnownProtocolKind(ip)); assert(proto && "missing Copyable/Escapable from stdlib!"); // Handle protocols specially, without building a GenericSignature. if (auto *protoDecl = dyn_cast(this)) { return protoDecl->inheritsFrom(proto) ? TypeDecl::CanBeInvertible::Always : TypeDecl::CanBeInvertible::Never; } Type selfTy = getDeclaredInterfaceType(); assert(selfTy); auto conformance = swift::lookupConformance(selfTy, proto, /*allowMissing=*/false); if (conformance.isInvalid()) return TypeDecl::CanBeInvertible::Never; if (!conformance.getConditionalRequirements().empty()) return TypeDecl::CanBeInvertible::Conditionally; return TypeDecl::CanBeInvertible::Always; } TypeDecl::CanBeInvertible::Result NominalTypeDecl::canBeCopyable() const { return canConformTo(InvertibleProtocolKind::Copyable); } TypeDecl::CanBeInvertible::Result NominalTypeDecl::canBeEscapable() const { return canConformTo(InvertibleProtocolKind::Escapable); } Type TypeDecl::getDeclaredInterfaceType() const { if (auto *NTD = dyn_cast(this)) return NTD->getDeclaredInterfaceType(); if (auto *ATD = dyn_cast(this)) { auto &ctx = getASTContext(); auto selfTy = getDeclContext()->getSelfInterfaceType(); if (!selfTy) return ErrorType::get(ctx); return DependentMemberType::get( selfTy, const_cast(ATD)); } return getInterfaceType()->getMetatypeInstanceType(); } int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) { // Order based on the enclosing declaration. auto dc1 = type1->getDeclContext(); auto dc2 = type2->getDeclContext(); // Prefer lower depths. auto depth1 = dc1->getSemanticDepth(); auto depth2 = dc2->getSemanticDepth(); if (depth1 != depth2) return depth1 < depth2 ? -1 : +1; // Prefer module names earlier in the alphabet. if (dc1->isModuleScopeContext() && dc2->isModuleScopeContext()) { auto module1 = dc1->getParentModule(); auto module2 = dc2->getParentModule(); if (int result = module1->getName().str().compare(module2->getName().str())) return result; } auto nominal1 = dc1->getSelfNominalTypeDecl(); auto nominal2 = dc2->getSelfNominalTypeDecl(); if (static_cast(nominal1) != static_cast(nominal2)) { return static_cast(nominal1) ? -1 : +1; } if (nominal1 && nominal2) { if (int result = compare(nominal1, nominal2)) return result; } if (int result = type1->getBaseIdentifier().str().compare( type2->getBaseIdentifier().str())) return result; // Error case: two type declarations that cannot be distinguished. if (type1 < type2) return -1; if (type1 > type2) return +1; return 0; } bool NominalTypeDecl::isFormallyResilient() const { // Private and (unversioned) internal types always have a // fixed layout. if (!getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true).isPublicOrPackage()) return false; // Check for an explicit @_fixed_layout or @frozen attribute. if (getAttrs().hasAttribute() || getAttrs().hasAttribute()) { return false; } // Structs and enums imported from C *always* have a fixed layout. // We know their size, and pass them as values in SIL and IRGen. if (hasClangNode()) return false; // @objc enums and protocols always have a fixed layout. if ((isa(this) || isa(this)) && isObjC()) return false; // Otherwise, the declaration behaves as if it was accessed via indirect // "resilient" interfaces, even if the module is not built with resilience. return true; } bool NominalTypeDecl::isResilient() const { if (!isFormallyResilient()) return false; return getModuleContext()->isResilient(); } bool NominalTypeDecl::isStrictlyResilient() const { return isResilient() && !getModuleContext()->allowNonResilientAccess(); } DestructorDecl *NominalTypeDecl::getValueTypeDestructor() { if (!isa(this) && !isa(this)) { return nullptr; } auto found = lookupDirect(DeclBaseName::createDestructor()); if (found.size() != 1) { return nullptr; } return cast(found[0]); } static bool isOriginallyDefinedIn(const Decl *D, const ModuleDecl* MD) { if (!MD) return false; if (D->getAlternateModuleName().empty()) return false; return D->getAlternateModuleName() == MD->getName().str(); } bool NominalTypeDecl::isResilient(ModuleDecl *M, ResilienceExpansion expansion) const { switch (expansion) { case ResilienceExpansion::Minimal: return isResilient(); case ResilienceExpansion::Maximal: // We can access declarations from the same module // non-resiliently in a maximal context. if (M == getModuleContext()) return false; // Access non-resiliently if package optimization is enabled if (bypassResilienceInPackage(M)) return false; // If a protocol is originally declared in the current module, then we // directly expose protocol witness tables and their contents for any // conformances in the same module as symbols. If the protocol later // moves, then we need to preserve those extra symbols from the home // module by treating the protocol as if it was still defined in the same // module. // // This logic does not and should not generally extend to other kinds of // declaration. If a declaration moves to a new module with library // evolution enabled, then even the original module has to access it // according to the library evolution ABI. This is an ABI compatibility // hack only for protocols. If you see other variations of `isResilient` // that don't check `isOriginallyDefinedIn`, they are probably correct. if (isa(this) && isOriginallyDefinedIn(this, M)) { return false; } // Otherwise, we have to access the declaration resiliently if it's // resilient anywhere. return isResilient(); } llvm_unreachable("bad resilience expansion"); } enum class DeclTypeKind : unsigned { DeclaredType, DeclaredInterfaceType }; static Type computeNominalType(NominalTypeDecl *decl, DeclTypeKind kind) { ASTContext &ctx = decl->getASTContext(); // Special case the Builtin.TheTupleType singleton. if (isa(decl)) return ctx.getBuiltinTupleType(); // If `decl` is a nested type, find the parent type. Type ParentTy; DeclContext *dc = decl->getDeclContext(); bool isUnsupportedNestedProtocol = isa(decl) && decl->getParent()->isGenericContext(); if (!isUnsupportedNestedProtocol && dc->isTypeContext()) { switch (kind) { case DeclTypeKind::DeclaredType: { if (auto *nominal = dc->getSelfNominalTypeDecl()) ParentTy = nominal->getDeclaredType(); break; } case DeclTypeKind::DeclaredInterfaceType: ParentTy = dc->getDeclaredInterfaceType(); if (ParentTy->is()) ParentTy = Type(); break; } } if (!isa(decl) && decl->getGenericParams()) { switch (kind) { case DeclTypeKind::DeclaredType: return UnboundGenericType::get(decl, ParentTy, ctx); case DeclTypeKind::DeclaredInterfaceType: { // Note that here, we need to be able to produce a type // before the decl has been validated, so we rely on // the generic parameter list directly instead of looking // at the signature. SmallVector args; for (auto param : decl->getGenericParams()->getParams()) { auto argTy = param->getDeclaredInterfaceType(); if (param->isParameterPack()) argTy = PackType::getSingletonPackExpansion(argTy); args.push_back(argTy); } return BoundGenericType::get(decl, ParentTy, args); } } llvm_unreachable("Unhandled DeclTypeKind in switch."); } return NominalType::get(decl, ParentTy, ctx); } Type NominalTypeDecl::getDeclaredType() const { if (DeclaredTy) return DeclaredTy; auto *decl = const_cast(this); decl->DeclaredTy = computeNominalType(decl, DeclTypeKind::DeclaredType); return DeclaredTy; } Type NominalTypeDecl::getDeclaredInterfaceType() const { if (DeclaredInterfaceTy) return DeclaredInterfaceTy; auto *decl = const_cast(this); decl->DeclaredInterfaceTy = computeNominalType(decl, DeclTypeKind::DeclaredInterfaceType); return DeclaredInterfaceTy; } void NominalTypeDecl::prepareExtensions() { // Types in local contexts can't have extensions if (getLocalContext() != nullptr) { return; } auto &context = Decl::getASTContext(); // If our list of extensions is out of date, update it now. if (context.getCurrentGeneration() > ExtensionGeneration) { unsigned previousGeneration = ExtensionGeneration; ExtensionGeneration = context.getCurrentGeneration(); context.loadExtensions(this, previousGeneration); } } ExtensionRange NominalTypeDecl::getExtensions() { prepareExtensions(); return ExtensionRange(ExtensionIterator(FirstExtension), ExtensionIterator()); } void NominalTypeDecl::addExtension(ExtensionDecl *extension) { assert(!extension->NextExtension.getInt() && "Already added extension"); extension->NextExtension.setInt(true); // First extension; set both first and last. if (!FirstExtension) { FirstExtension = extension; LastExtension = extension; addedExtension(extension); return; } // Add to the end of the list. LastExtension->NextExtension.setPointer(extension); LastExtension = extension; addedExtension(extension); } ArrayRef NominalTypeDecl::getStoredProperties() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, StoredPropertiesRequest{mutableThis}, {}); } ArrayRef NominalTypeDecl::getInitAccessorProperties() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, InitAccessorPropertiesRequest{mutableThis}, {}); } ArrayRef NominalTypeDecl::getMemberwiseInitProperties() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, MemberwiseInitPropertiesRequest{mutableThis}, {}); } void NominalTypeDecl::collectPropertiesInitializableByInitAccessors( std::multimap &result) const { for (auto *property : getInitAccessorProperties()) { auto *initAccessor = property->getAccessor(AccessorKind::Init); for (auto *subsumed : initAccessor->getInitializedProperties()) result.insert({subsumed, property}); } } ArrayRef NominalTypeDecl::getStoredPropertiesAndMissingMemberPlaceholders() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, StoredPropertiesAndMissingMembersRequest{mutableThis}, {}); } bool NominalTypeDecl::isOptionalDecl() const { return this == getASTContext().getOptionalDecl(); } std::optional NominalTypeDecl::getKeyPathTypeKind() const { auto &ctx = getASTContext(); #define CASE(NAME) if (this == ctx.get##NAME##Decl()) return KPTK_##NAME; CASE(KeyPath) CASE(WritableKeyPath) CASE(ReferenceWritableKeyPath) CASE(AnyKeyPath) CASE(PartialKeyPath) #undef CASE return std::nullopt; } PropertyWrapperTypeInfo NominalTypeDecl::getPropertyWrapperTypeInfo() const { ASTContext &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, PropertyWrapperTypeInfoRequest{mutableThis}, PropertyWrapperTypeInfo()); } bool NominalTypeDecl::isActor() const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, IsActorRequest{mutableThis}, false); } bool NominalTypeDecl::isDistributedActor() const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, IsDistributedActorRequest{mutableThis}, false); } bool NominalTypeDecl::isAnyActor() const { return isActor() || isDistributedActor(); } bool NominalTypeDecl::isMainActor() const { return getName().is("MainActor") && getParentModule()->getName() == getASTContext().Id_Concurrency; } bool NominalTypeDecl::suppressesConformance(KnownProtocolKind kp) const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, SuppressesConformanceRequest{mutableThis, kp}, false); } GenericTypeDecl::GenericTypeDecl(DeclKind K, DeclContext *DC, Identifier name, SourceLoc nameLoc, ArrayRef inherited, GenericParamList *GenericParams) : GenericContext(DeclContextKind::GenericTypeDecl, DC, GenericParams), TypeDecl(K, DC, name, nameLoc, inherited) {} TypeAliasDecl::TypeAliasDecl(SourceLoc TypeAliasLoc, SourceLoc EqualLoc, Identifier Name, SourceLoc NameLoc, GenericParamList *GenericParams, DeclContext *DC) : GenericTypeDecl(DeclKind::TypeAlias, DC, Name, NameLoc, {}, GenericParams), TypeAliasLoc(TypeAliasLoc), EqualLoc(EqualLoc) { Bits.TypeAliasDecl.IsCompatibilityAlias = false; Bits.TypeAliasDecl.IsDebuggerAlias = false; } SourceRange TypeAliasDecl::getSourceRange() const { auto TrailingWhereClauseSourceRange = getGenericTrailingWhereClauseSourceRange(); if (TrailingWhereClauseSourceRange.isValid()) return { TypeAliasLoc, TrailingWhereClauseSourceRange.End }; if (UnderlyingTy.hasLocation()) return { TypeAliasLoc, UnderlyingTy.getSourceRange().End }; if (TypeEndLoc.isValid()) return { TypeAliasLoc, TypeEndLoc }; return { TypeAliasLoc, getNameLoc() }; } Type TypeAliasDecl::getUnderlyingType() const { auto &ctx = getASTContext(); if (auto type = evaluateOrDefault(ctx.evaluator, UnderlyingTypeRequest{const_cast(this)}, Type())) return type; return ErrorType::get(ctx); } void TypeAliasDecl::setUnderlyingType(Type underlying) { // lldb creates global typealiases containing archetypes // sometimes... assert(!underlying->hasArchetype() || !isGenericContext()); getASTContext().evaluator.cacheOutput( StructuralTypeRequest{const_cast(this)}, std::move(underlying)); getASTContext().evaluator.cacheOutput( UnderlyingTypeRequest{const_cast(this)}, std::move(underlying)); } UnboundGenericType *TypeAliasDecl::getUnboundGenericType() const { assert(getGenericParams()); Type parentTy; auto parentDC = getDeclContext(); if (auto nominal = parentDC->getSelfNominalTypeDecl()) parentTy = nominal->getDeclaredType(); return UnboundGenericType::get( const_cast(this), parentTy, getASTContext()); } Type TypeAliasDecl::getStructuralType() const { auto &ctx = getASTContext(); if (auto type = evaluateOrDefault( ctx.evaluator, StructuralTypeRequest{const_cast(this)}, Type())) return type; return ErrorType::get(ctx); } GenericTypeParamDecl::GenericTypeParamDecl(DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc specifierLoc, unsigned depth, unsigned index, GenericTypeParamKind paramKind, bool isOpaqueType, TypeRepr *opaqueTypeRepr) : TypeDecl(DeclKind::GenericTypeParam, dc, name, nameLoc, {}) { ASSERT(!(specifierLoc && !(paramKind == GenericTypeParamKind::Pack || paramKind == GenericTypeParamKind::Value)) && "'each' or 'let' keyword imply a parameter pack or value generic parameter"); ASSERT(isOpaqueType || !opaqueTypeRepr); Bits.GenericTypeParamDecl.Depth = depth; assert(Bits.GenericTypeParamDecl.Depth == depth && "Truncation"); Bits.GenericTypeParamDecl.Index = index; assert(Bits.GenericTypeParamDecl.Index == index && "Truncation"); Bits.GenericTypeParamDecl.ParamKind = (uint8_t) paramKind; Bits.GenericTypeParamDecl.IsOpaqueType = isOpaqueType; if (this->isOpaqueType()) *getTrailingObjects() = opaqueTypeRepr; if (this->isParameterPack()) *getTrailingObjects() = specifierLoc; if (this->isValue()) *getTrailingObjects() = specifierLoc; } GenericTypeParamDecl *GenericTypeParamDecl::create( DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc specifierLoc, unsigned depth, unsigned index, GenericTypeParamKind paramKind, bool isOpaqueType, TypeRepr *opaqueTypeRepr) { auto &ctx = dc->getASTContext(); auto numTypeReprs = 0; if (isOpaqueType) numTypeReprs = 1; auto numSourceLocs = 0; if (paramKind == GenericTypeParamKind::Pack || paramKind == GenericTypeParamKind::Value) numSourceLocs = 1; auto allocSize = totalSizeToAlloc(numTypeReprs, numSourceLocs); auto mem = ctx.Allocate(allocSize, alignof(GenericTypeParamDecl)); return new (mem) GenericTypeParamDecl(dc, name, nameLoc, specifierLoc, depth, index, paramKind, isOpaqueType, opaqueTypeRepr); } GenericTypeParamDecl *GenericTypeParamDecl::createDeserialized( DeclContext *dc, Identifier name, unsigned depth, unsigned index, GenericTypeParamKind paramKind, bool isOpaqueType) { return GenericTypeParamDecl::create(dc, name, SourceLoc(), SourceLoc(), depth, index, paramKind, isOpaqueType, /*opaqueRepr*/ nullptr); } GenericTypeParamDecl * GenericTypeParamDecl::createParsed(DeclContext *dc, Identifier name, SourceLoc nameLoc, SourceLoc specifierLoc, unsigned index, GenericTypeParamKind paramKind) { // We always create generic type parameters with an invalid depth. // Semantic analysis fills in the depth when it processes the generic // parameter list. return GenericTypeParamDecl::create( dc, name, nameLoc, specifierLoc, GenericTypeParamDecl::InvalidDepth, index, paramKind, /*isOpaqueType*/ false, /*opaqueTypeRepr*/ nullptr); } GenericTypeParamDecl *GenericTypeParamDecl::createImplicit( DeclContext *dc, Identifier name, unsigned depth, unsigned index, GenericTypeParamKind paramKind, TypeRepr *opaqueTypeRepr, SourceLoc nameLoc, SourceLoc specifierLoc) { auto *param = GenericTypeParamDecl::create(dc, name, nameLoc, specifierLoc, depth, index, paramKind, (bool)opaqueTypeRepr, opaqueTypeRepr); param->setImplicit(); return param; } Type GenericTypeParamDecl::getValueType() const { return evaluateOrDefault(getASTContext().evaluator, GenericTypeParamDeclGetValueTypeRequest{const_cast(this)}, Type()); } SourceRange GenericTypeParamDecl::getSourceRange() const { auto startLoc = getNameLoc(); auto endLoc = getNameLoc(); if (const auto specifierLoc = getSpecifierLoc()) startLoc = specifierLoc; if (!getInherited().empty()) { if (getInherited().getEndLoc().isValid()) endLoc = getInherited().getEndLoc(); else assert(startLoc.isInvalid() || this->hasClangNode()); } return {startLoc, endLoc}; } AssociatedTypeDecl::AssociatedTypeDecl(DeclContext *dc, SourceLoc keywordLoc, Identifier name, SourceLoc nameLoc, TypeRepr *defaultDefinition, TrailingWhereClause *trailingWhere) : TypeDecl(DeclKind::AssociatedType, dc, name, nameLoc, { }), KeywordLoc(keywordLoc), DefaultDefinition(defaultDefinition), TrailingWhere(trailingWhere) { Bits.AssociatedTypeDecl.IsDefaultDefinitionTypeComputed = false; } AssociatedTypeDecl * AssociatedTypeDecl::createParsed(ASTContext &ctx, DeclContext *dc, SourceLoc keywordLoc, Identifier name, SourceLoc nameLoc, TypeRepr *defaultDefinition, TrailingWhereClause *trailingWhere) { auto *decl = new (ctx) AssociatedTypeDecl(dc, keywordLoc, name, nameLoc, defaultDefinition, trailingWhere); // Sort out this trivial case now to enable the AST dumper to differentiate // between a nonexistent and null default type without having to trigger a // request. if (!defaultDefinition) decl->setDefaultDefinitionType(nullptr); return decl; } AssociatedTypeDecl *AssociatedTypeDecl::createDeserialized( ASTContext &ctx, DeclContext *dc, SourceLoc keywordLoc, Identifier name, SourceLoc nameLoc, TrailingWhereClause *trailingWhere, LazyMemberLoader *lazyLoader, uint64_t defaultDefinitionTypeData) { assert(lazyLoader && "missing lazy member loader"); auto *decl = new (ctx) AssociatedTypeDecl(dc, keywordLoc, name, nameLoc, /*defaultDefinition*/ nullptr, trailingWhere); // Sort out this trivial case now to enable the AST dumper to differentiate // between a nonexistent and null default type without having to trigger a // request. '0' is the sentinel ID for no data. if (defaultDefinitionTypeData == 0) { decl->setDefaultDefinitionType(nullptr); } else { auto *data = static_cast( ctx.getOrCreateLazyContextData(decl, lazyLoader)); data->defaultDefinitionTypeData = defaultDefinitionTypeData; } return decl; } Type AssociatedTypeDecl::getDefaultDefinitionType() const { return evaluateOrDefault(getASTContext().evaluator, DefaultDefinitionTypeRequest{const_cast(this)}, Type()); } std::optional AssociatedTypeDecl::getCachedDefaultDefinitionType() const { if (Bits.AssociatedTypeDecl.IsDefaultDefinitionTypeComputed) return DefaultDefinition.getType(); return std::nullopt; } void AssociatedTypeDecl::setDefaultDefinitionType(Type ty) { DefaultDefinition.setType(ty); Bits.AssociatedTypeDecl.IsDefaultDefinitionTypeComputed = true; } SourceRange AssociatedTypeDecl::getSourceRange() const { SourceLoc endLoc; if (auto TWC = getTrailingWhereClause()) { endLoc = TWC->getSourceRange().End; } else if (auto defaultDefinition = getDefaultDefinitionTypeRepr()) { endLoc = defaultDefinition->getEndLoc(); } else if (!getInherited().empty()) { endLoc = getInherited().getEndLoc(); } else { endLoc = getNameLoc(); } return SourceRange(KeywordLoc, endLoc); } llvm::TinyPtrVector AssociatedTypeDecl::getOverriddenDecls() const { // FIXME: Performance hack because we end up looking at the overridden // declarations of an associated type a *lot*. OverriddenDeclsRequest request{const_cast(this)}; llvm::TinyPtrVector overridden; if (auto cached = request.getCachedResult()) overridden = std::move(*cached); else overridden = TypeDecl::getOverriddenDecls(); llvm::TinyPtrVector assocTypes; for (auto decl : overridden) { assocTypes.push_back(cast(decl)); } return assocTypes; } namespace { static AssociatedTypeDecl *getAssociatedTypeAnchor( const AssociatedTypeDecl *ATD, llvm::SmallSet &searched) { auto overridden = ATD->getOverriddenDecls(); // If this declaration does not override any other declarations, it's // the anchor. if (overridden.empty()) return const_cast(ATD); // Find the best anchor among the anchors of the overridden decls and avoid // reentrancy when erroneous cyclic protocols exist. AssociatedTypeDecl *bestAnchor = nullptr; for (auto assocType : overridden) { if (!searched.insert(assocType).second) continue; auto anchor = getAssociatedTypeAnchor(assocType, searched); if (!anchor) continue; if (!bestAnchor || TypeDecl::compare(anchor, bestAnchor) < 0) bestAnchor = anchor; } return bestAnchor; } } AssociatedTypeDecl *AssociatedTypeDecl::getAssociatedTypeAnchor() const { llvm::SmallSet searched; return ::getAssociatedTypeAnchor(this, searched); } EnumDecl::EnumDecl(SourceLoc EnumLoc, Identifier Name, SourceLoc NameLoc, ArrayRef Inherited, GenericParamList *GenericParams, DeclContext *Parent) : NominalTypeDecl(DeclKind::Enum, Parent, Name, NameLoc, Inherited, GenericParams), EnumLoc(EnumLoc) { Bits.EnumDecl.HasAssociatedValues = static_cast(AssociatedValueCheck::Unchecked); Bits.EnumDecl.HasAnyUnavailableValues = false; } Type EnumDecl::getRawType() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, EnumRawTypeRequest{const_cast(this)}, ErrorType::get(ctx)); } void EnumDecl::setRawType(Type rawType) { getASTContext().evaluator.cacheOutput(EnumRawTypeRequest{this}, std::move(rawType)); } StructDecl::StructDecl(SourceLoc StructLoc, Identifier Name, SourceLoc NameLoc, ArrayRef Inherited, GenericParamList *GenericParams, DeclContext *Parent) : NominalTypeDecl(DeclKind::Struct, Parent, Name, NameLoc, Inherited, GenericParams), StructLoc(StructLoc) { Bits.StructDecl.HasUnreferenceableStorage = false; Bits.StructDecl.IsCxxNonTrivial = false; } bool NominalTypeDecl::hasMemberwiseInitializer() const { // Currently only structs can have memberwise initializers. auto *sd = dyn_cast(this); if (!sd) return false; auto &ctx = getASTContext(); auto *mutableThis = const_cast(sd); return evaluateOrDefault(ctx.evaluator, HasMemberwiseInitRequest{mutableThis}, false); } ConstructorDecl *NominalTypeDecl::getMemberwiseInitializer() const { if (!hasMemberwiseInitializer()) return nullptr; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, SynthesizeMemberwiseInitRequest{mutableThis}, nullptr); } ConstructorDecl *NominalTypeDecl::getEffectiveMemberwiseInitializer() { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ResolveEffectiveMemberwiseInitRequest{mutableThis}, nullptr); } bool NominalTypeDecl::hasDefaultInitializer() const { // Currently only structs and classes can have default initializers. if (!isa(this) && !isa(this)) return false; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, HasDefaultInitRequest{mutableThis}, false); } bool NominalTypeDecl::isTypeErasedGenericClass() const { // ObjC classes are type erased. // TODO: Unless they have magic methods... if (auto clazz = dyn_cast(this)) return clazz->isTypeErasedGenericClass(); return false; } ConstructorDecl *NominalTypeDecl::getDefaultInitializer() const { if (!hasDefaultInitializer()) return nullptr; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, SynthesizeDefaultInitRequest{mutableThis}, nullptr); } void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) { // Silently break cycles here because we can't be sure when and where a // request to synthesize will come from yet. // FIXME: rdar://56844567 if (Bits.NominalTypeDecl.IsComputingSemanticMembers) return; Bits.NominalTypeDecl.IsComputingSemanticMembers = true; SWIFT_DEFER { Bits.NominalTypeDecl.IsComputingSemanticMembers = false; }; auto baseName = member.getBaseName(); auto &Context = getASTContext(); std::optional action = std::nullopt; if (baseName.isConstructor()) action.emplace(ImplicitMemberAction::ResolveImplicitInit); if (member.isSimpleName() && !baseName.isSpecial()) { if (baseName.getIdentifier() == getASTContext().Id_CodingKeys) { action.emplace(ImplicitMemberAction::ResolveCodingKeys); } } else { auto argumentNames = member.getArgumentNames(); if (member.isSimpleName() || argumentNames.size() == 1) { if (baseName.isConstructor()) { if ((member.isSimpleName() || argumentNames.front() == Context.Id_from)) { action.emplace(ImplicitMemberAction::ResolveDecodable); } else if (argumentNames.front() == Context.Id_system) { action.emplace(ImplicitMemberAction::ResolveDistributedActorSystem); } } else if (!baseName.isSpecial() && baseName.getIdentifier() == Context.Id_encode && (member.isSimpleName() || argumentNames.front() == Context.Id_to)) { action.emplace(ImplicitMemberAction::ResolveEncodable); } } else if (member.isSimpleName() || argumentNames.size() == 2) { if (baseName.isConstructor()) { if (argumentNames[0] == Context.Id_resolve && argumentNames[1] == Context.Id_using) { action.emplace(ImplicitMemberAction::ResolveDistributedActor); } } } } if (auto actionToTake = action) { (void)evaluateOrDefault(Context.evaluator, ResolveImplicitMemberRequest{this, actionToTake.value()}, {}); } } VarDecl *NominalTypeDecl::getGlobalActorInstance() const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, GlobalActorInstanceRequest{mutableThis}, nullptr); } AbstractFunctionDecl * NominalTypeDecl::getExecutorOwnedEnqueueFunction() const { auto &C = getASTContext(); StructDecl *executorJobDecl = C.getExecutorJobDecl(); if (!executorJobDecl) return nullptr; auto proto = dyn_cast(this); if (!proto) return nullptr; llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { // we're specifically looking for the Executor protocol requirement if (!isa(candidate->getDeclContext())) continue; if (auto *funcDecl = dyn_cast(candidate)) { auto params = funcDecl->getParameters(); if (params->size() != 1) continue; if ((params->get(0)->getSpecifier() == ParamSpecifier::LegacyOwned || params->get(0)->getSpecifier() == ParamSpecifier::Consuming) && params->get(0)->getInterfaceType()->isEqual(executorJobDecl->getDeclaredInterfaceType())) { return funcDecl; } } } return nullptr; } AbstractFunctionDecl * NominalTypeDecl::getExecutorLegacyOwnedEnqueueFunction() const { auto &C = getASTContext(); StructDecl *legacyJobDecl = C.getJobDecl(); if (!legacyJobDecl) return nullptr; auto proto = dyn_cast(this); if (!proto) return nullptr; llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { // we're specifically looking for the Executor protocol requirement if (!isa(candidate->getDeclContext())) continue; if (auto *funcDecl = dyn_cast(candidate)) { auto params = funcDecl->getParameters(); if (params->size() != 1) continue; if ((params->get(0)->getSpecifier() == ParamSpecifier::LegacyOwned || params->get(0)->getSpecifier() == ParamSpecifier::Consuming) && params->get(0)->getInterfaceType()->isEqual(legacyJobDecl->getDeclaredInterfaceType())) { return funcDecl; } } } return nullptr; } AbstractFunctionDecl * NominalTypeDecl::getExecutorLegacyUnownedEnqueueFunction() const { auto &C = getASTContext(); StructDecl *unownedJobDecl = C.getUnownedJobDecl(); if (!unownedJobDecl) return nullptr; auto proto = dyn_cast(this); if (!proto) return nullptr; llvm::SmallVector results; lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_enqueue), getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { // we're specifically looking for the Executor protocol requirement if (!isa(candidate->getDeclContext())) continue; if (auto *funcDecl = dyn_cast(candidate)) { auto params = funcDecl->getParameters(); if (params->size() != 1) continue; auto param = params->get(0); if (param->getSpecifier() == ParamSpecifier::LegacyOwned || param->getSpecifier() == ParamSpecifier::Consuming) { return funcDecl; } } } return nullptr; } ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc, ArrayRef Inherited, GenericParamList *GenericParams, DeclContext *Parent, bool isActor) : NominalTypeDecl(DeclKind::Class, Parent, Name, NameLoc, Inherited, GenericParams), ClassLoc(ClassLoc) { Bits.ClassDecl.InheritsSuperclassInits = 0; Bits.ClassDecl.ComputedInheritsSuperclassInits = 0; Bits.ClassDecl.RawForeignKind = 0; Bits.ClassDecl.HasMissingDesignatedInitializers = 0; Bits.ClassDecl.ComputedHasMissingDesignatedInitializers = 0; Bits.ClassDecl.HasMissingVTableEntries = 0; Bits.ClassDecl.ComputedHasMissingVTableEntries = 0; Bits.ClassDecl.IsIncompatibleWithWeakReferences = 0; Bits.ClassDecl.IsActor = isActor; } bool ClassDecl::hasResilientMetadata() const { // Imported classes don't have a vtable, etc, at all. if (hasClangNode()) return false; // If the module is not resilient, neither is the class metadata. if (!getModuleContext()->isResilient()) return false; // If the class is not public or package, we can't use it outside the module at all. // Take enable testing into account. if (getEffectiveAccess() < AccessLevel::Package) return false; // Otherwise we access metadata members, such as vtable entries, resiliently. return true; } bool ClassDecl::hasResilientMetadata(ModuleDecl *M, ResilienceExpansion expansion) const { switch (expansion) { case ResilienceExpansion::Minimal: return hasResilientMetadata(); case ResilienceExpansion::Maximal: return M != getModuleContext() && hasResilientMetadata(); } llvm_unreachable("bad resilience expansion"); } DestructorDecl *ClassDecl::getDestructor() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, GetDestructorRequest{const_cast(this)}, nullptr); } /// Synthesizer callback for an empty implicit function body. static std::pair synthesizeEmptyFunctionBody(AbstractFunctionDecl *afd, void *context) { ASTContext &ctx = afd->getASTContext(); return { BraceStmt::create(ctx, afd->getLoc(), { }, afd->getLoc(), true), /*isTypeChecked=*/true }; } DestructorDecl * GetDestructorRequest::evaluate(Evaluator &evaluator, ClassDecl *CD) const { auto dc = CD->getImplementationContext(); auto &ctx = CD->getASTContext(); auto *DD = new (ctx) DestructorDecl(CD->getLoc(), dc->getAsGenericContext()); DD->setImplicit(); // Synthesize an empty body for the destructor as needed. DD->setBodySynthesizer(synthesizeEmptyFunctionBody); // Propagate access control and versioned-ness. DD->copyFormalAccessFrom(CD, /*sourceIsParentContext*/true); // Mark DD as ObjC, as all dtors are. DD->setIsObjC(ctx.LangOpts.EnableObjCInterop); if (ctx.LangOpts.EnableObjCInterop) CD->recordObjCMethod(DD, DD->getObjCSelector()); // Mark it as synthesized to make its location in getEmittedMembers() // deterministic. DD->setSynthesized(true); return DD; } bool ClassDecl::isDefaultActor() const { return isDefaultActor(getModuleContext(), ResilienceExpansion::Minimal); } bool ClassDecl::isDefaultActor(ModuleDecl *M, ResilienceExpansion expansion) const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, IsDefaultActorRequest{mutableThis, M, expansion}, false); } const ClassDecl *ClassDecl::getRootActorClass() const { if (!isActor()) return nullptr; auto cur = this; while (true) { auto super = cur->getSuperclassDecl(); if (!super || !super->isActor()) return cur; cur = super; } } bool ClassDecl::hasMissingDesignatedInitializers() const { return evaluateOrDefault( getASTContext().evaluator, HasMissingDesignatedInitializersRequest{const_cast(this)}, false); } bool ClassDecl::hasMissingVTableEntries() const { if (!Bits.ClassDecl.ComputedHasMissingVTableEntries) { auto *mutableThis = const_cast(this); mutableThis->Bits.ClassDecl.ComputedHasMissingVTableEntries = 1; mutableThis->loadAllMembers(); } return Bits.ClassDecl.HasMissingVTableEntries; } bool ClassDecl::isIncompatibleWithWeakReferences() const { if (Bits.ClassDecl.IsIncompatibleWithWeakReferences) { return true; } if (auto superclass = getSuperclassDecl()) { return superclass->isIncompatibleWithWeakReferences(); } return false; } bool ClassDecl::inheritsSuperclassInitializers() const { // If there's no superclass, there's nothing to inherit. if (!getSuperclassDecl()) return false; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, InheritsSuperclassInitializersRequest{mutableThis}, false); } AncestryOptions ClassDecl::checkAncestry() const { return AncestryOptions(evaluateOrDefault(getASTContext().evaluator, ClassAncestryFlagsRequest{const_cast(this)}, AncestryFlags())); } AncestryFlags ClassAncestryFlagsRequest::evaluate(Evaluator &evaluator, ClassDecl *value) const { AncestryOptions result; const ClassDecl *CD = value; const ClassDecl *PreviousCD = nullptr; auto *M = value->getParentModule(); do { if (CD->isGenericContext()) result |= AncestryFlags::Generic; // Note: it's OK to check for @objc explicitly instead of calling isObjC() // to infer it since we're going to visit every superclass. if (CD->getAttrs().hasAttribute()) result |= AncestryFlags::ObjC; if (CD->getAttrs().hasAttribute()) result |= AncestryFlags::ObjCMembers; if (CD->hasClangNode()) { result |= AncestryFlags::ClangImported; // Inheriting from an ObjC-defined class generally forces the use // of the ObjC object model, but certain classes that directly // inherit from NSObject can change that. if (!PreviousCD || !(CD->isNSObject() && PreviousCD->isNativeNSObjectSubclass())) result |= AncestryFlags::ObjCObjectModel; } if (CD->hasResilientMetadata()) result |= AncestryFlags::Resilient; if (CD->hasResilientMetadata(M, ResilienceExpansion::Maximal)) result |= AncestryFlags::ResilientOther; if (CD->getAttrs().hasAttribute()) result |= AncestryFlags::RequiresStoredPropertyInits; PreviousCD = CD; CD = CD->getSuperclassDecl(); } while (CD != nullptr); return AncestryFlags(result.toRaw()); } void swift::simple_display(llvm::raw_ostream &out, AncestryFlags value) { AncestryOptions opts(value); out << "{ "; // If we have more than one bit set, we need to print the separator. bool wantsSeparator = false; auto printBit = [&wantsSeparator, &out](bool val, StringRef name) { if (wantsSeparator) { out << ", "; } if (!wantsSeparator) { wantsSeparator = true; } out << name; if (val) { out << " = true"; } else { out << " = false"; } }; printBit(opts.contains(AncestryFlags::ObjC), "ObjC"); printBit(opts.contains(AncestryFlags::ObjCMembers), "ObjCMembers"); printBit(opts.contains(AncestryFlags::Generic), "Generic"); printBit(opts.contains(AncestryFlags::Resilient), "Resilient"); printBit(opts.contains(AncestryFlags::ResilientOther), "ResilientOther"); printBit(opts.contains(AncestryFlags::ClangImported), "ClangImported"); printBit(opts.contains(AncestryFlags::RequiresStoredPropertyInits), "RequiresStoredPropertyInits"); out << " }"; } bool ClassDecl::isSuperclassOf(const ClassDecl *other) const { llvm::SmallPtrSet visited; do { if (!visited.insert(other).second) break; if (this == other) return true; other = other->getSuperclassDecl(); } while (other != nullptr); return false; } ClassDecl::MetaclassKind ClassDecl::getMetaclassKind() const { assert(getASTContext().LangOpts.EnableObjCInterop && "querying metaclass kind without objc interop"); auto objc = checkAncestry(AncestryFlags::ObjC); return objc ? MetaclassKind::ObjC : MetaclassKind::SwiftStub; } /// Mangle the name of a protocol or class for use in the Objective-C /// runtime. static StringRef mangleObjCRuntimeName(const NominalTypeDecl *nominal, llvm::SmallVectorImpl &buffer) { { Mangle::ASTMangler Mangler; std::string MangledName = Mangler.mangleObjCRuntimeName(nominal); buffer.clear(); llvm::raw_svector_ostream os(buffer); os << MangledName; } assert(buffer.size() && "Invalid buffer size"); return StringRef(buffer.data(), buffer.size()); } StringRef ClassDecl::getObjCRuntimeName( llvm::SmallVectorImpl &buffer) const { // If there is a Clang declaration, use it's runtime name. if (auto objcClass = dyn_cast_or_null(getClangDecl())) return objcClass->getObjCRuntimeNameAsString(); // If there is an 'objc' attribute with a name, use that name. if (auto attr = getAttrs().getAttribute()) return attr->Name; if (auto objc = getAttrs().getAttribute()) { if (auto name = objc->getName()) return name->getString(buffer); } // Produce the mangled name for this class. return mangleObjCRuntimeName(this, buffer); } ArtificialMainKind Decl::getArtificialMainKind() const { if (getAttrs().hasAttribute()) return ArtificialMainKind::UIApplicationMain; if (getAttrs().hasAttribute()) return ArtificialMainKind::NSApplicationMain; if (isa(this)) return ArtificialMainKind::TypeMain; llvm_unreachable("type has no @Main attr?!"); } static bool isOverridingDecl(const ValueDecl *Derived, const ValueDecl *Base) { while (Derived) { if (Derived == Base) return true; Derived = Derived->getOverriddenDecl(); } return false; } static ValueDecl *findOverridingDecl(const ClassDecl *C, const ValueDecl *Base) { // FIXME: This is extremely inefficient. The SILOptimizer should build a // reverse lookup table to answer these types of queries. for (auto M : C->getMembers()) { if (auto *Derived = dyn_cast(M)) if (::isOverridingDecl(Derived, Base)) return Derived; } return nullptr; } AbstractFunctionDecl * ClassDecl::findOverridingDecl(const AbstractFunctionDecl *Method) const { if (auto *Accessor = dyn_cast(Method)) { auto *Storage = Accessor->getStorage(); if (auto *Derived = ::findOverridingDecl(this, Storage)) { auto *DerivedStorage = cast(Derived); return DerivedStorage->getOpaqueAccessor(Accessor->getAccessorKind()); } return nullptr; } return cast_or_null(::findOverridingDecl(this, Method)); } AbstractFunctionDecl * ClassDecl::findImplementingMethod(const AbstractFunctionDecl *Method) const { // FIXME: This is extremely inefficient. The SILOptimizer should build a // reverse lookup table to answer these types of queries. const ClassDecl *C = this; while (C) { if (C == Method->getDeclContext()) return const_cast(Method); if (auto *Derived = C->findOverridingDecl(Method)) return Derived; // Check the superclass C = C->getSuperclassDecl(); } return nullptr; } bool ClassDecl::walkSuperclasses( llvm::function_ref fn) const { auto *cls = const_cast(this); while (cls) { switch (fn(cls)) { case TypeWalker::Action::Stop: return true; case TypeWalker::Action::SkipNode: return false; case TypeWalker::Action::Continue: cls = cls->getSuperclassDecl(); continue; } } return false; } bool ClassDecl::isForeignReferenceType() const { auto clangRecordDecl = dyn_cast_or_null(getClangDecl()); if (!clangRecordDecl) return false; CxxRecordSemanticsKind kind = evaluateOrDefault( getASTContext().evaluator, CxxRecordSemantics({clangRecordDecl, getASTContext()}), {}); return kind == CxxRecordSemanticsKind::Reference; } bool ClassDecl::hasRefCountingAnnotations() const { return evaluateOrDefault(getASTContext().evaluator, CustomRefCountingOperation( {this, CustomRefCountingOperationKind::release}), {}) .kind != CustomRefCountingOperationResult::immortal; } ReferenceCounting ClassDecl::getObjectModel() const { if (isForeignReferenceType()) return hasRefCountingAnnotations() ? ReferenceCounting::Custom : ReferenceCounting::None; if (checkAncestry(AncestryFlags::ObjCObjectModel)) return ReferenceCounting::ObjC; return ReferenceCounting::Native; } EnumCaseDecl *EnumCaseDecl::create(SourceLoc CaseLoc, ArrayRef Elements, DeclContext *DC) { size_t bytes = totalSizeToAlloc(Elements.size()); void *buf = DC->getASTContext().Allocate(bytes, alignof(EnumCaseDecl)); return ::new (buf) EnumCaseDecl(CaseLoc, Elements, DC); } bool EnumDecl::hasPotentiallyUnavailableCaseValue() const { (void)this->hasOnlyCasesWithoutAssociatedValues(); // Prime the cache return static_cast(Bits.EnumDecl.HasAnyUnavailableValues); } bool EnumDecl::hasCasesUnavailableDuringLowering() const { (void)this->hasOnlyCasesWithoutAssociatedValues(); // Prime the cache return static_cast(Bits.EnumDecl.HasAnyUnavailableDuringLoweringValues); } bool EnumDecl::hasOnlyCasesWithoutAssociatedValues() const { // Check whether we already have a cached answer. switch (static_cast( Bits.EnumDecl.HasAssociatedValues)) { case AssociatedValueCheck::Unchecked: // Compute below. break; case AssociatedValueCheck::NoAssociatedValues: return true; case AssociatedValueCheck::HasAssociatedValues: return false; } bool hasAnyUnavailableValues = false; bool hasAnyUnavailableDuringLoweringValues = false; bool hasAssociatedValues = false; for (auto elt : getAllElements()) { for (auto Attr : elt->getAttrs()) { if (auto AvAttr = dyn_cast(Attr)) { if (!AvAttr->isInvalid()) hasAnyUnavailableValues = true; } } if (!elt->isAvailableDuringLowering()) hasAnyUnavailableDuringLoweringValues = true; if (elt->hasAssociatedValues()) hasAssociatedValues = true; } EnumDecl *enumDecl = const_cast(this); enumDecl->Bits.EnumDecl.HasAnyUnavailableValues = hasAnyUnavailableValues; enumDecl->Bits.EnumDecl.HasAnyUnavailableDuringLoweringValues = hasAnyUnavailableDuringLoweringValues; enumDecl->Bits.EnumDecl.HasAssociatedValues = static_cast( hasAssociatedValues ? AssociatedValueCheck::HasAssociatedValues : AssociatedValueCheck::NoAssociatedValues); return !hasAssociatedValues; } bool EnumDecl::treatAsExhaustiveForDiags(const DeclContext *useDC) const { return isFormallyExhaustive(useDC) || (useDC && getModuleContext()->inSamePackage(useDC->getParentModule())); } bool EnumDecl::isFormallyExhaustive(const DeclContext *useDC) const { // Enums explicitly marked frozen are exhaustive. if (getAttrs().hasAttribute()) return true; // Objective-C enums /not/ marked frozen are /not/ exhaustive. // Note: This implicitly holds @objc enums defined in Swift to a higher // standard! if (hasClangNode()) return false; // Non-imported enums in non-resilient modules are exhaustive. const ModuleDecl *containingModule = getModuleContext(); if (!containingModule->isResilient()) return true; // Non-public, non-versioned enums are always exhaustive. AccessScope accessScope = getFormalAccessScope(/*useDC*/ nullptr, /*respectVersioned*/ true); if (!accessScope.isPublicOrPackage()) return true; // All other checks are use-site specific; with no further information, the // enum must be treated non-exhaustively. if (!useDC) return false; // Enums in the same module as the use site are exhaustive /unless/ the use // site is inlinable. if (useDC->getParentModule() == containingModule) if (useDC->getResilienceExpansion() == ResilienceExpansion::Maximal) return true; // Testably imported enums are exhaustive, on the grounds that only the author // of the original library can import it testably. if (auto *useSF = dyn_cast(useDC->getModuleScopeContext())) if (useSF->hasTestableOrPrivateImport(AccessLevel::Internal, containingModule)) return true; // Otherwise, the enum is non-exhaustive. return false; } bool EnumDecl::isEffectivelyExhaustive(ModuleDecl *M, ResilienceExpansion expansion) const { // Generated Swift code commits to handling garbage values of @objc enums, // whether imported or not, to deal with C's loose rules around enums. // This covers both frozen and non-frozen @objc enums. if (isObjC()) return false; // Otherwise, the only non-exhaustive enums are those that don't have // a fixed layout; however, they are treated as exhaustive if package // optimization is enabled. assert((isFormallyExhaustive(M) || bypassResilienceInPackage(M)) == !isResilient(M, ResilienceExpansion::Maximal) && "ignoring the effects of @inlinable, @testable, and @objc, " "these should match up"); return !isResilient(M, expansion); } void EnumDecl::setHasFixedRawValues() { SemanticFlags |= OptionSet{EnumDecl::HasFixedRawValues}; } bool EnumDecl::hasCircularRawValue() const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, HasCircularRawValueRequest{mutableThis}, true); } ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc, SourceLoc NameLoc, Identifier Name, ArrayRef PrimaryAssociatedTypeNames, ArrayRef Inherited, TrailingWhereClause *TrailingWhere) : NominalTypeDecl(DeclKind::Protocol, DC, Name, NameLoc, Inherited, nullptr), ProtocolLoc(ProtocolLoc), PrimaryAssociatedTypeNames(PrimaryAssociatedTypeNames) { Bits.ProtocolDecl.RequiresClassValid = false; Bits.ProtocolDecl.RequiresClass = false; Bits.ProtocolDecl.ExistentialConformsToSelfValid = false; Bits.ProtocolDecl.ExistentialConformsToSelf = false; Bits.ProtocolDecl.InheritedProtocolsValid = false; Bits.ProtocolDecl.AllInheritedProtocolsValid = false; Bits.ProtocolDecl.HasMissingRequirements = false; Bits.ProtocolDecl.KnownProtocol = 0; Bits.ProtocolDecl.HasAssociatedTypes = false; Bits.ProtocolDecl.HasLazyAssociatedTypes = false; Bits.ProtocolDecl.HasRequirementSignature = false; Bits.ProtocolDecl.HasLazyRequirementSignature = false; Bits.ProtocolDecl.ProtocolRequirementsValid = false; setTrailingWhereClause(TrailingWhere); } bool ProtocolDecl::isMarkerProtocol() const { return getAttrs().hasAttribute(); } std::optional ProtocolDecl::getInvertibleProtocolKind() const { if (auto kp = getKnownProtocolKind()) return ::getInvertibleProtocolKind(*kp); return std::nullopt; } ObjCRequirementMap ProtocolDecl::getObjCRequiremenMap() const { ObjCRequirementMap defaultMap; if (!isObjC()) return defaultMap; return evaluateOrDefault(getASTContext().evaluator, ObjCRequirementMapRequest{this}, defaultMap); } ArrayRef ProtocolDecl::getInheritedProtocols() const { auto *mutThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, InheritedProtocolsRequest{mutThis}, {}); } ArrayRef ProtocolDecl::getAllInheritedProtocols() const { // Avoid evaluator overhead because we call this from Symbol::compare() // in the Requirement Machine. if (Bits.ProtocolDecl.AllInheritedProtocolsValid) return AllInheritedProtocols; auto *mutThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, AllInheritedProtocolsRequest{mutThis}, {}); } ArrayRef ProtocolDecl::getAssociatedTypeMembers() const { if (Bits.ProtocolDecl.HasAssociatedTypes) return AssociatedTypes; auto *self = const_cast(this); self->Bits.ProtocolDecl.HasAssociatedTypes = 1; // Clang-imported protocols never have associated types. if (hasClangNode()) return ArrayRef(); // Deserialized @objc protocols never have associated types. if (getParentSourceFile() == nullptr && isObjC()) return ArrayRef(); SmallVector result; if (Bits.ProtocolDecl.HasLazyAssociatedTypes) { auto &ctx = getASTContext(); auto contextData = static_cast( ctx.getOrCreateLazyContextData(this, nullptr)); contextData->loader->loadAssociatedTypes( this, contextData->associatedTypesData, result); } else { for (auto member : getProtocolRequirements()) { if (auto ATD = dyn_cast(member)) { result.push_back(ATD); } } } self->AssociatedTypes = getASTContext().AllocateCopy(result); return AssociatedTypes; } ArrayRef ProtocolDecl::getProtocolRequirements() const { auto *mutableSelf = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, ProtocolRequirementsRequest{mutableSelf}, {}); } ValueDecl *ProtocolDecl::getSingleRequirement(DeclName name) const { auto results = const_cast(this)->lookupDirect(name); ValueDecl *result = nullptr; for (auto candidate : results) { if (candidate->getDeclContext() != this || !candidate->isProtocolRequirement()) continue; if (result) { // Multiple results. return nullptr; } result = candidate; } return result; } AssociatedTypeDecl *ProtocolDecl::getAssociatedType(Identifier name) const { auto results = const_cast(this)->lookupDirect(name); for (auto candidate : results) { if (candidate->getDeclContext() == this && isa(candidate)) { return cast(candidate); } } return nullptr; } ClassDecl *ProtocolDecl::getSuperclassDecl() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, SuperclassDeclRequest{const_cast(this)}, nullptr); } bool ProtocolDecl::walkInheritedProtocols( llvm::function_ref fn) const { auto self = const_cast(this); // Visit all of the inherited protocols. SmallPtrSet visited; SmallVector stack; stack.push_back(self); visited.insert(self); while (!stack.empty()) { // Pull the next protocol off the stack. auto proto = stack.back(); stack.pop_back(); switch (fn(proto)) { case TypeWalker::Action::Stop: return true; case TypeWalker::Action::Continue: // Add inherited protocols to the stack. for (auto inherited : proto->getInheritedProtocols()) { if (visited.insert(inherited).second) stack.push_back(inherited); } break; case TypeWalker::Action::SkipNode: break; } } return false; } bool ProtocolDecl::inheritsFrom(const ProtocolDecl *super) const { assert(super); // Fast path. if (this == super) return false; auto allInherited = getAllInheritedProtocols(); return (llvm::find(allInherited, super) != allInherited.end()); } bool ProtocolDecl::requiresClass() const { return evaluateOrDefault(getASTContext().evaluator, ProtocolRequiresClassRequest{const_cast(this)}, false); } bool ProtocolDecl::requiresSelfConformanceWitnessTable() const { return isSpecificProtocol(KnownProtocolKind::Error); } bool ProtocolDecl::existentialConformsToSelf() const { return evaluateOrDefault(getASTContext().evaluator, ExistentialConformsToSelfRequest{const_cast(this)}, true); } bool ProtocolDecl::hasSelfOrAssociatedTypeRequirements() const { return evaluateOrDefault(getASTContext().evaluator, HasSelfOrAssociatedTypeRequirementsRequest{ const_cast(this)}, true); } bool ProtocolDecl::existentialRequiresAny() const { if (getASTContext().LangOpts.hasFeature(Feature::ExistentialAny)) return true; return hasSelfOrAssociatedTypeRequirements(); } ArrayRef ProtocolDecl::getPrimaryAssociatedTypes() const { return evaluateOrDefault(getASTContext().evaluator, PrimaryAssociatedTypesRequest{const_cast(this)}, nullptr); } StringRef ProtocolDecl::getObjCRuntimeName( llvm::SmallVectorImpl &buffer) const { // If there is an 'objc' attribute with a name, use that name. if (auto objc = getAttrs().getAttribute()) { if (auto name = objc->getName()) return name->getString(buffer); } // Produce the mangled name for this protocol. return mangleObjCRuntimeName(this, buffer); } ArrayRef ProtocolDecl::getStructuralRequirements() const { return evaluateOrDefault( getASTContext().evaluator, StructuralRequirementsRequest{const_cast(this)}, {}); } ArrayRef ProtocolDecl::getTypeAliasRequirements() const { return evaluateOrDefault( getASTContext().evaluator, TypeAliasRequirementsRequest{const_cast(this)}, {}); } ArrayRef ProtocolDecl::getProtocolDependencies() const { return evaluateOrDefault( getASTContext().evaluator, ProtocolDependenciesRequest{const_cast(this)}, std::nullopt); } RequirementSignature ProtocolDecl::getRequirementSignature() const { return getASTContext().evaluator( RequirementSignatureRequest{const_cast(this)}, [this]() { return RequirementSignature::getPlaceholderRequirementSignature( this, GenericSignatureErrors()); }); } bool ProtocolDecl::isComputingRequirementSignature() const { return getASTContext().evaluator.hasActiveRequest( RequirementSignatureRequest{const_cast(this)}); } void ProtocolDecl::setRequirementSignature(RequirementSignature requirementSig) { RequirementSig = requirementSig; Bits.ProtocolDecl.HasRequirementSignature = 1; } void ProtocolDecl::setLazyRequirementSignature(LazyMemberLoader *lazyLoader, uint64_t requirementSignatureData) { assert(!isRequirementSignatureComputed() && "requirement signature already set"); auto contextData = static_cast( getASTContext().getOrCreateLazyContextData(this, lazyLoader)); contextData->requirementSignatureData = requirementSignatureData; Bits.ProtocolDecl.HasLazyRequirementSignature = true; ++NumLazyRequirementSignatures; // FIXME: (transitional) increment the redundant "always-on" counter. if (auto *Stats = getASTContext().Stats) ++Stats->getFrontendCounters().NumLazyRequirementSignatures; } void ProtocolDecl::setLazyAssociatedTypeMembers( LazyMemberLoader *lazyLoader, uint64_t associatedTypesData) { assert(!Bits.ProtocolDecl.HasAssociatedTypes); assert(!Bits.ProtocolDecl.HasLazyAssociatedTypes); auto contextData = static_cast( getASTContext().getOrCreateLazyContextData(this, lazyLoader)); contextData->associatedTypesData = associatedTypesData; Bits.ProtocolDecl.HasLazyAssociatedTypes = true; } void ProtocolDecl::setLazyPrimaryAssociatedTypeMembers( LazyMemberLoader *lazyLoader, uint64_t associatedTypesData) { assert(!Bits.ProtocolDecl.HasLazyPrimaryAssociatedTypes); auto contextData = static_cast( getASTContext().getOrCreateLazyContextData(this, lazyLoader)); contextData->primaryAssociatedTypesData = associatedTypesData; Bits.ProtocolDecl.HasLazyPrimaryAssociatedTypes = true; } void ProtocolDecl::computeKnownProtocolKind() const { auto module = getModuleContext(); if (module != module->getASTContext().getStdlibModule() && module != module->getASTContext().TheBuiltinModule && !module->getName().is("Foundation") && !module->getName().is("_Differentiation") && !module->getName().is("_Concurrency") && !module->getName().is("Distributed")) { const_cast(this)->Bits.ProtocolDecl.KnownProtocol = 1; return; } unsigned value = llvm::StringSwitch(getBaseName().userFacingName()) #define PROTOCOL_WITH_NAME(Id, Name) \ .Case(Name, static_cast(KnownProtocolKind::Id) + 2) #include "swift/AST/KnownProtocols.def" .Default(1); const_cast(this)->Bits.ProtocolDecl.KnownProtocol = value; } std::optional ProtocolDecl::getKnownDerivableProtocolKind() const { const auto knownKind = getKnownProtocolKind(); if (!knownKind) return std::nullopt; switch (*knownKind) { case KnownProtocolKind::RawRepresentable: return KnownDerivableProtocolKind::RawRepresentable; case KnownProtocolKind::OptionSet: return KnownDerivableProtocolKind::OptionSet; case KnownProtocolKind::CaseIterable: return KnownDerivableProtocolKind::CaseIterable; case KnownProtocolKind::Comparable: return KnownDerivableProtocolKind::Comparable; case KnownProtocolKind::Equatable: return KnownDerivableProtocolKind::Equatable; case KnownProtocolKind::Hashable: return KnownDerivableProtocolKind::Hashable; case KnownProtocolKind::BridgedNSError: return KnownDerivableProtocolKind::BridgedNSError; case KnownProtocolKind::CodingKey: return KnownDerivableProtocolKind::CodingKey; case KnownProtocolKind::Encodable: return KnownDerivableProtocolKind::Encodable; case KnownProtocolKind::Decodable: return KnownDerivableProtocolKind::Decodable; case KnownProtocolKind::AdditiveArithmetic: return KnownDerivableProtocolKind::AdditiveArithmetic; case KnownProtocolKind::Differentiable: return KnownDerivableProtocolKind::Differentiable; case KnownProtocolKind::Identifiable: return KnownDerivableProtocolKind::Identifiable; case KnownProtocolKind::Actor: return KnownDerivableProtocolKind::Actor; case KnownProtocolKind::DistributedActor: return KnownDerivableProtocolKind::DistributedActor; case KnownProtocolKind::DistributedActorSystem: return KnownDerivableProtocolKind::DistributedActorSystem; default: return std::nullopt; } } bool ProtocolDecl::hasCircularInheritedProtocols() const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, HasCircularInheritedProtocolsRequest{mutableThis}, true); } /// Returns a descriptive name for the given accessor/addressor kind. StringRef swift::getAccessorNameForDiagnostic(AccessorKind accessorKind, bool article) { switch (accessorKind) { case AccessorKind::Get: return article ? "a getter" : "getter"; case AccessorKind::DistributedGet: return article ? "a distributed getter" : "distributed getter"; case AccessorKind::Set: return article ? "a setter" : "setter"; case AccessorKind::Address: return article ? "an addressor" : "addressor"; case AccessorKind::MutableAddress: return article ? "a mutable addressor" : "mutable addressor"; case AccessorKind::Read: case AccessorKind::Read2: return article ? "a 'read' accessor" : "'read' accessor"; case AccessorKind::Modify: case AccessorKind::Modify2: return article ? "a 'modify' accessor" : "'modify' accessor"; case AccessorKind::WillSet: return "'willSet'"; case AccessorKind::DidSet: return "'didSet'"; case AccessorKind::Init: return article ? "an init accessor" : "init accessor"; } llvm_unreachable("bad accessor kind"); } StringRef swift::getAccessorNameForDiagnostic(AccessorDecl *accessor, bool article) { return getAccessorNameForDiagnostic(accessor->getAccessorKind(), article); } bool AbstractStorageDecl::hasStorage() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, HasStorageRequest{const_cast(this)}, false); } StorageImplInfo AbstractStorageDecl::getImplInfo() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, StorageImplInfoRequest{const_cast(this)}, StorageImplInfo::getSimpleStored(StorageIsMutable)); } void AbstractStorageDecl::cacheImplInfo(StorageImplInfo implInfo) { LazySemanticInfo.ImplInfoComputed = 1; ImplInfo = implInfo; } void AbstractStorageDecl::setImplInfo(StorageImplInfo implInfo) { cacheImplInfo(implInfo); if (isImplicit()) { if (!LazySemanticInfo.HasStorageComputed) { LazySemanticInfo.HasStorageComputed = true; LazySemanticInfo.HasStorage = implInfo.hasStorage(); } else { assert(LazySemanticInfo.HasStorage == implInfo.hasStorage()); } } } bool AbstractStorageDecl::hasPrivateAccessor() const { for (auto accessor : getAllAccessors()) { if (hasPrivateOrFilePrivateFormalAccess(accessor)) return true; } return false; } bool AbstractStorageDecl::hasDidSetOrWillSetDynamicReplacement() const { if (auto *func = getParsedAccessor(AccessorKind::DidSet)) return (bool)func->getDynamicallyReplacedDecl(); if (auto *func = getParsedAccessor(AccessorKind::WillSet)) return (bool)func->getDynamicallyReplacedDecl(); return false; } bool AbstractStorageDecl::hasAnyNativeDynamicAccessors() const { for (auto accessor : getAllAccessors()) { if (accessor->shouldUseNativeDynamicDispatch()) return true; } return false; } void AbstractStorageDecl::setAccessors(SourceLoc lbraceLoc, ArrayRef accessors, SourceLoc rbraceLoc) { // This method is called after we've already recorded an accessors clause // only on recovery paths and only when that clause was empty, or when a // macro expands to accessors (in which case, we may already have accessors). auto record = Accessors.getPointer(); if (record) { for (auto accessor : accessors) { if (!record->getAccessor(accessor->getAccessorKind())) (void) record->addOpaqueAccessor(accessor); } } else { record = AccessorRecord::create(getASTContext(), SourceRange(lbraceLoc, rbraceLoc), accessors); Accessors.setPointer(record); } } // Compute the number of opaque accessors. const size_t NumOpaqueAccessors = 0 #define ACCESSOR(ID) #define OPAQUE_ACCESSOR(ID, KEYWORD) \ + 1 #include "swift/AST/AccessorKinds.def" ; AbstractStorageDecl::AccessorRecord * AbstractStorageDecl::AccessorRecord::create(ASTContext &ctx, SourceRange braces, ArrayRef accessors) { // Silently cap the number of accessors we store at a number that should // be easily sufficient for all the valid cases, including space for adding // implicit opaque accessors later. // // We should have already emitted a diagnostic in the parser if we have // this many accessors, because most of them will necessarily be redundant. if (accessors.size() + NumOpaqueAccessors > MaxNumAccessors) { accessors = accessors.slice(0, MaxNumAccessors - NumOpaqueAccessors); } // Make sure that we have enough space to add implicit opaque accessors later. size_t numMissingOpaque = NumOpaqueAccessors; { #define ACCESSOR(ID) #define OPAQUE_ACCESSOR(ID, KEYWORD) \ bool has##ID = false; #include "swift/AST/AccessorKinds.def" for (auto accessor : accessors) { switch (accessor->getAccessorKind()) { #define ACCESSOR(ID) \ case AccessorKind::ID: \ continue; #define OPAQUE_ACCESSOR(ID, KEYWORD) \ case AccessorKind::ID: \ if (!has##ID) { \ has##ID = true; \ --numMissingOpaque; \ } \ continue; #include "swift/AST/AccessorKinds.def" } llvm_unreachable("bad accessor kind"); } } auto accessorsCapacity = AccessorIndex(accessors.size() + numMissingOpaque); void *mem = ctx.Allocate(totalSizeToAlloc(accessorsCapacity), alignof(AccessorRecord)); return new (mem) AccessorRecord(braces, accessors, accessorsCapacity); } AbstractStorageDecl::AccessorRecord::AccessorRecord(SourceRange braces, ArrayRef accessors, AccessorIndex accessorsCapacity) : Braces(braces), NumAccessors(accessors.size()), AccessorsCapacity(accessorsCapacity), AccessorIndices{} { // Copy the complete accessors list into place. memcpy(getAccessorsBuffer().data(), accessors.data(), accessors.size() * sizeof(AccessorDecl*)); // Register all the accessors. for (auto index : indices(accessors)) { (void) registerAccessor(accessors[index], index); } } void AbstractStorageDecl::AccessorRecord::addOpaqueAccessor(AccessorDecl *decl){ assert(decl); // Add the accessor to the array. assert(NumAccessors < AccessorsCapacity); AccessorIndex index = NumAccessors++; getAccessorsBuffer()[index] = decl; // Register it. bool isUnique = registerAccessor(decl, index); assert(isUnique && "adding opaque accessor that's already present"); (void) isUnique; } void AbstractStorageDecl::AccessorRecord::removeAccessor( AccessorDecl *accessor ) { // Remove this accessor from the list of accessors. assert(getAccessor(accessor->getAccessorKind()) == accessor); (void)std::remove(getAccessorsBuffer().begin(), getAccessorsBuffer().end(), accessor); // Clear out the accessor kind -> index mapping. std::memset(AccessorIndices, 0, sizeof(AccessorIndices)); // Re-add all of the remaining accessors to build up the index mapping. unsigned numAccessorsLeft = NumAccessors - 1; NumAccessors = numAccessorsLeft; auto buffer = getAccessorsBuffer(); NumAccessors = 0; for (auto index : range(0, numAccessorsLeft)) { addOpaqueAccessor(buffer[index]); } } /// Register that we have an accessor of the given kind. bool AbstractStorageDecl::AccessorRecord::registerAccessor(AccessorDecl *decl, AccessorIndex index){ // Remember that we have at least one accessor of this kind. auto &indexSlot = AccessorIndices[unsigned(decl->getAccessorKind())]; if (indexSlot) { return false; } else { indexSlot = index + 1; assert(getAccessor(decl->getAccessorKind()) == decl); return true; } } AccessLevel AbstractStorageDecl::getSetterFormalAccess() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, SetterAccessLevelRequest{const_cast(this)}, AccessLevel::Private); } AccessScope AbstractStorageDecl::getSetterFormalAccessScope(const DeclContext *useDC, bool treatUsableFromInlineAsPublic) const { return getAccessScopeForFormalAccess(this, getSetterFormalAccess(), useDC, treatUsableFromInlineAsPublic); } void AbstractStorageDecl::setComputedSetter(AccessorDecl *setter) { assert(getImplInfo().getReadImpl() == ReadImplKind::Get); assert(!getImplInfo().supportsMutation()); assert(getAccessor(AccessorKind::Get) && "invariant check: missing getter"); assert(!getAccessor(AccessorKind::Set) && "already has a setter"); assert(hasClangNode() && "should only be used for ObjC properties"); assert(setter && "should not be called for readonly properties"); assert(setter->getAccessorKind() == AccessorKind::Set); setImplInfo(StorageImplInfo::getMutableComputed()); Accessors.getPointer()->addOpaqueAccessor(setter); } void AbstractStorageDecl::setSynthesizedAccessor(AccessorKind kind, AccessorDecl *accessor) { assert(!getAccessor(kind) && "accessor already exists"); assert(accessor->getAccessorKind() == kind); auto accessors = Accessors.getPointer(); if (!accessors) { accessors = AccessorRecord::create(getASTContext(), SourceRange(), {}); Accessors.setPointer(accessors); } accessors->addOpaqueAccessor(accessor); } static std::optional getNameFromObjcAttribute(const ObjCAttr *attr, DeclName preferredName) { if (!attr) return std::nullopt; if (auto name = attr->getName()) { if (attr->isNameImplicit()) { // preferredName > implicit name, because implicit name is just cached // actual name. if (!preferredName) return *name; } else { // explicit name > preferred name. return *name; } } return std::nullopt; } ObjCSelector AbstractStorageDecl::getObjCGetterSelector(Identifier preferredName) const { // If the getter has an @objc attribute with a name, use that. if (auto getter = getAccessor(AccessorKind::Get)) { if (auto name = getNameFromObjcAttribute(getter->getAttrs(). getAttribute(), preferredName)) return *name; } // Subscripts use a specific selector. auto &ctx = getASTContext(); if (auto *SD = dyn_cast(this)) { switch (SD->getObjCSubscriptKind()) { case ObjCSubscriptKind::Indexed: return ObjCSelector(ctx, 1, ctx.Id_objectAtIndexedSubscript); case ObjCSubscriptKind::Keyed: return ObjCSelector(ctx, 1, ctx.Id_objectForKeyedSubscript); } } // The getter selector is the property name itself. auto var = cast(this); auto name = var->getObjCPropertyName(); // Use preferred name is specified. if (!preferredName.empty()) name = preferredName; return VarDecl::getDefaultObjCGetterSelector(ctx, name); } ObjCSelector AbstractStorageDecl::getObjCSetterSelector(Identifier preferredName) const { // If the setter has an @objc attribute with a name, use that. auto setter = getAccessor(AccessorKind::Set); auto objcAttr = setter ? setter->getAttrs().getAttribute() : nullptr; if (auto name = getNameFromObjcAttribute(objcAttr, DeclName(preferredName))) { return *name; } // Subscripts use a specific selector. auto &ctx = getASTContext(); if (auto *SD = dyn_cast(this)) { switch (SD->getObjCSubscriptKind()) { case ObjCSubscriptKind::Indexed: return ObjCSelector(ctx, 2, { ctx.Id_setObject, ctx.Id_atIndexedSubscript }); case ObjCSubscriptKind::Keyed: return ObjCSelector(ctx, 2, { ctx.Id_setObject, ctx.Id_forKeyedSubscript }); } } // The setter selector for, e.g., 'fooBar' is 'setFooBar:', with the // property name capitalized and preceded by 'set'. auto var = cast(this); Identifier Name = var->getObjCPropertyName(); if (!preferredName.empty()) Name = preferredName; auto result = VarDecl::getDefaultObjCSetterSelector(ctx, Name); // Cache the result, so we don't perform string manipulation again. if (objcAttr && preferredName.empty()) const_cast(objcAttr)->setName(result, /*implicit=*/true); return result; } SourceLoc AbstractStorageDecl::getOverrideLoc() const { if (auto *Override = getAttrs().getAttribute()) return Override->getLocation(); return SourceLoc(); } Type AbstractStorageDecl::getValueInterfaceType() const { if (auto var = dyn_cast(this)) return var->getInterfaceType()->getReferenceStorageReferent(); return cast(this)->getElementInterfaceType(); } bool AbstractStorageDecl::hasInitAccessor() const { return evaluateOrDefault( getASTContext().evaluator, HasInitAccessorRequest{const_cast(this)}, false); } VarDecl::VarDecl(DeclKind kind, bool isStatic, VarDecl::Introducer introducer, SourceLoc nameLoc, Identifier name, DeclContext *dc, StorageIsMutable_t supportsMutation) : AbstractStorageDecl(kind, isStatic, dc, name, nameLoc, supportsMutation) { Bits.VarDecl.Introducer = unsigned(introducer); Bits.VarDecl.IsSelfParamCapture = false; Bits.VarDecl.IsDebuggerVar = false; Bits.VarDecl.IsLazyStorageProperty = false; Bits.VarDecl.IsPropertyWrapperBackingProperty = false; Bits.VarDecl.IsTopLevelGlobal = false; Bits.VarDecl.NoAttachedPropertyWrappers = false; Bits.VarDecl.NoPropertyWrapperAuxiliaryVariables = false; } Type VarDecl::getTypeInContext() const { return getDeclContext()->mapTypeIntoContext(getInterfaceType()); } /// Translate an "is mutable" bit into a StorageMutability value. static StorageMutability storageIsMutable(bool isMutable) { return isMutable ? StorageMutability::Mutable : StorageMutability::Immutable; } /// Returns whether the var is settable in the specified context: this /// is either because it is a stored var, because it has a custom setter, or /// is a let member in an initializer. StorageMutability VarDecl::mutability(const DeclContext *UseDC, std::optional base) const { // Parameters are settable or not depending on their ownership convention. if (auto *PD = dyn_cast(this)) return storageIsMutable(!PD->isImmutableInFunctionBody()); // If this is a 'var' decl, then we're settable if we have storage or a // setter. if (!isLet()) { if (hasInitAccessor()) { if (auto *ctor = dyn_cast_or_null(UseDC)) { // If we're referencing 'self.', it's mutable. if (!base || (*base && ctor->getImplicitSelfDecl() == (*base)->getDecl())) return StorageMutability::Mutable; return storageIsMutable(supportsMutation()); } } return storageIsMutable(supportsMutation()); } // Static 'let's are always immutable. if (isStatic()) { return StorageMutability::Immutable; } // // All the remaining logic handles the special cases where you can // assign a 'let'. // // Debugger expression 'let's are initialized through a side-channel. if (isDebuggerVar()) return StorageMutability::Immutable; // 'let's are only ever settable from a specific DeclContext. if (UseDC == nullptr) return StorageMutability::Immutable; // 'let' properties in structs/classes are only ever settable in their // designated initializer(s) or by init accessors. if (isInstanceMember()) { // Init accessors allow assignments to `let` properties if a // property is part of `initializes` list. if (auto *accessor = dyn_cast(const_cast(UseDC))) { // Check whether this property is part of `initializes` list, // and allow assignment/mutation if so. DI would be responsible // for checking for re-assignment. if (accessor->isInitAccessor() && llvm::is_contained(accessor->getInitializedProperties(), const_cast(this))) return StorageMutability::Initializable; return StorageMutability::Immutable; } auto *CD = dyn_cast(UseDC); if (!CD) return StorageMutability::Immutable; auto *CDC = CD->getDeclContext(); // 'let' properties are not valid inside protocols. if (CDC->getExtendedProtocolDecl()) return StorageMutability::Immutable; // If this init is defined inside of the same type (or in an extension // thereof) as the let property, then it is mutable. if (CDC->getSelfNominalTypeDecl() != getDeclContext()->getSelfNominalTypeDecl()) return StorageMutability::Immutable; // If this is a convenience initializer (i.e. one that calls // self.init), then let properties are never mutable in it. They are // only mutable in designated initializers. auto initKindAndExpr = CD->getDelegatingOrChainedInitKind(); if (initKindAndExpr.initKind == BodyInitKind::Delegating) return StorageMutability::Immutable; // If we were given a base and it is 'self', it's initializable. if (!base || (*base && CD->getImplicitSelfDecl() == (*base)->getDecl())) { // Treat values of tuple type as mutable in these contexts, because // SILGen wants to see them as lvalues. if (getInterfaceType()->is()) return StorageMutability::Mutable; return StorageMutability::Initializable; } return StorageMutability::Immutable; } // If the 'let' has a value bound to it but has no PBD, then it is // already initializedand not settable. if (getParentPatternBinding() == nullptr) return StorageMutability::Immutable; // If the 'let' has an explicitly written initializer with a pattern binding, // then it isn't settable. if (isParentInitialized()) return StorageMutability::Immutable; // Normal lets (e.g. globals) are only mutable in the context of the // declaration. To handle top-level code properly, we look through // the TopLevelCode decl on the use (if present) since the vardecl may be // one level up. if (getDeclContext() == UseDC) { // Treat values of tuple type as mutable in these contexts, because // SILGen wants to see them as lvalues. if (getInterfaceType()->is()) return StorageMutability::Mutable; return StorageMutability::Initializable; } if (isa(UseDC) && getDeclContext() == UseDC->getParent()) return StorageMutability::Initializable; return StorageMutability::Immutable; } bool VarDecl::isLazilyInitializedGlobal() const { assert(!getDeclContext()->isLocalContext() && "not a global variable!"); assert(hasStorage() && "not a stored global variable!"); // Imports from C are never lazily initialized. if (hasClangNode()) return false; if (isDebuggerVar()) return false; if (getAttrs().hasAttribute()) return false; // Top-level global variables in the main source file and in the REPL are not // lazily initialized. return !isTopLevelGlobal(); } Expr *VarDecl::getParentExecutableInitializer() const { if (auto *PBD = getParentPatternBinding()) { const auto i = PBD->getPatternEntryIndexForVarDecl(this); return PBD->getExecutableInit(i); } return nullptr; } ActorIsolation VarDecl::getInitializerIsolation() const { auto *mutableThis = const_cast(this); return evaluateOrDefault( getASTContext().evaluator, DefaultInitializerIsolation{mutableThis}, ActorIsolation::forUnspecified()); } SourceRange VarDecl::getSourceRange() const { if (auto Param = dyn_cast(this)) return Param->getSourceRange(); return getNameLoc(); } SourceRange VarDecl::getTypeSourceRangeForDiagnostics() const { // For a parameter, map back to its parameter to get the TypeLoc. if (auto *PD = dyn_cast(this)) { if (auto typeRepr = PD->getTypeRepr()) return typeRepr->getSourceRange(); } Pattern *Pat = getParentPattern(); if (!Pat || Pat->isImplicit()) return SourceRange(); if (auto *VP = dyn_cast(Pat)) Pat = VP->getSubPattern(); if (auto *TP = dyn_cast(Pat)) if (auto typeRepr = TP->getTypeRepr()) return typeRepr->getSourceRange(); return SourceRange(); } static std::optional> findParentPatternCaseStmtAndPattern(const VarDecl *inputVD) { auto getMatchingPattern = [&](CaseStmt *cs) -> Pattern * { // Check if inputVD is in our case body var decls if we have any. If we do, // treat its pattern as our first case label item pattern. for (auto *vd : cs->getCaseBodyVariablesOrEmptyArray()) { if (vd == inputVD) { return cs->getMutableCaseLabelItems().front().getPattern(); } } // Then check the rest of our case label items. for (auto &item : cs->getMutableCaseLabelItems()) { if (item.getPattern()->containsVarDecl(inputVD)) { return item.getPattern(); } } // Otherwise return false if we do not find anything. return nullptr; }; // First find our canonical var decl. This is the VarDecl corresponding to the // first case label item of the first case block in the fallthrough chain that // our case block is within. Grab the case stmt associated with that var decl // and start traveling down the fallthrough chain looking for the case // statement that the input VD belongs to by using getMatchingPattern(). auto *canonicalVD = inputVD->getCanonicalVarDecl(); auto *caseStmt = dyn_cast_or_null(canonicalVD->getParentPatternStmt()); if (!caseStmt) return std::nullopt; if (auto *p = getMatchingPattern(caseStmt)) return std::make_pair(caseStmt, p); while ((caseStmt = caseStmt->getFallthroughDest().getPtrOrNull())) { if (auto *p = getMatchingPattern(caseStmt)) return std::make_pair(caseStmt, p); } return std::nullopt; } VarDecl *VarDecl::getCanonicalVarDecl() const { // Any var decl without a parent var decl is canonical. This means that before // type checking, all var decls are canonical. auto *cur = const_cast(this); auto *vd = cur->getParentVarDecl(); if (!vd) return cur; #ifndef NDEBUG // Make sure that we don't get into an infinite loop. SmallPtrSet visitedDecls; visitedDecls.insert(vd); visitedDecls.insert(cur); #endif while (vd) { cur = vd; vd = vd->getParentVarDecl(); assert((!vd || visitedDecls.insert(vd).second) && "Infinite loop ?!"); } return cur; } Stmt *VarDecl::getRecursiveParentPatternStmt() const { // If our parent is already a pattern stmt, just return that. if (auto *stmt = getParentPatternStmt()) return stmt; // Otherwise, see if we have a parent var decl. If we do not, then return // nullptr. Otherwise, return the case stmt that we found. auto result = findParentPatternCaseStmtAndPattern(this); if (!result.has_value()) return nullptr; return result->first; } /// Return the Pattern involved in initializing this VarDecl. Recall that the /// Pattern may be involved in initializing more than just this one vardecl /// though. For example, if this is a VarDecl for "x", the pattern may be /// "(x, y)" and the initializer on the PatternBindingDecl may be "(1,2)" or /// "foo()". /// /// If this has no parent pattern binding decl or statement associated, it /// returns null. /// Pattern *VarDecl::getParentPattern() const { // If this has a PatternBindingDecl parent, use its pattern. if (auto *PBD = getParentPatternBinding()) { const auto i = PBD->getPatternEntryIndexForVarDecl(this); return PBD->getPattern(i); } // If this is a statement parent, dig the pattern out of it. if (auto *stmt = getParentPatternStmt()) { if (auto *FES = dyn_cast(stmt)) return FES->getPattern(); if (auto *cs = dyn_cast(stmt)) { // In a case statement, search for the pattern that contains it. This is // a bit silly, because you can't have something like "case x, y:" anyway. for (auto items : cs->getCaseLabelItems()) { if (items.getPattern()->containsVarDecl(this)) return items.getPattern(); } } if (auto *LCS = dyn_cast(stmt)) { for (auto &elt : LCS->getCond()) if (auto pat = elt.getPatternOrNull()) if (pat->containsVarDecl(this)) return pat; } } // Otherwise, check if we have to walk our case stmt's var decl list to find // the pattern. if (auto caseStmtPatternPair = findParentPatternCaseStmtAndPattern(this)) { return caseStmtPatternPair->second; } // Otherwise, this is a case we do not know or understand. Return nullptr to // signal we do not have any information. return nullptr; } NamedPattern *VarDecl::getNamingPattern() const { return evaluateOrDefault(getASTContext().evaluator, NamingPatternRequest{const_cast(this)}, nullptr); } void VarDecl::setNamingPattern(NamedPattern *Pat) { getASTContext().evaluator.cacheOutput(NamingPatternRequest{this}, std::move(Pat)); } TypeRepr *VarDecl::getTypeReprOrParentPatternTypeRepr() const { if (auto *Param = dyn_cast(this)) return Param->getTypeRepr(); auto *ParentPattern = getParentPattern(); if (auto *TyPattern = dyn_cast_or_null(ParentPattern)) return TyPattern->getTypeRepr(); // Handle typed if/guard/while-let as a special case (e.g. `if let x: Int // = Optional.some(4)`), since the `TypedPattern` is not the top-level // pattern here - instead it is an implicit `OptionalSomePattern` if (auto *SomePattern = dyn_cast_or_null(ParentPattern)) { if (auto *TyPattern = dyn_cast(SomePattern->getSubPattern())) { return TyPattern->getTypeRepr(); } } return nullptr; } NullablePtr VarDecl::getCorrespondingFirstCaseLabelItemVarDecl() const { if (!hasName()) return nullptr; auto *caseStmt = dyn_cast_or_null(getRecursiveParentPatternStmt()); if (!caseStmt) return nullptr; auto *pattern = caseStmt->getCaseLabelItems().front().getPattern(); SmallVector vars; pattern->collectVariables(vars); for (auto *vd : vars) { if (vd->hasName() && vd->getName() == getName()) return vd; } return nullptr; } bool VarDecl::isCaseBodyVariable() const { auto *caseStmt = dyn_cast_or_null(getRecursiveParentPatternStmt()); if (!caseStmt) return false; return llvm::any_of(caseStmt->getCaseBodyVariablesOrEmptyArray(), [&](VarDecl *vd) { return vd == this; }); } NullablePtr VarDecl::getCorrespondingCaseBodyVariable() const { // Only var decls associated with case statements can have child var decls. auto *caseStmt = dyn_cast_or_null(getRecursiveParentPatternStmt()); if (!caseStmt) return nullptr; // If this var decl doesn't have a name, it can not have a corresponding case // body variable. if (!hasName()) return nullptr; auto name = getName(); // A var decl associated with a case stmt implies that the case stmt has body // var decls. So we can access the optional value here without worry. auto caseBodyVars = caseStmt->getCaseBodyVariables(); auto result = llvm::find_if(caseBodyVars, [&](VarDecl *caseBodyVar) { return caseBodyVar->getName() == name; }); return (result != caseBodyVars.end()) ? *result : nullptr; } bool VarDecl::isSelfParameter() const { if (isa(this)) { if (auto *AFD = dyn_cast(getDeclContext())) return AFD->getImplicitSelfDecl(/*createIfNeeded=*/false) == this; if (auto *PBI = dyn_cast(getDeclContext())) return PBI->getImplicitSelfDecl() == this; } return false; } bool VarDecl::isActorSelf() const { if (!isSelfParameter() && !isSelfParamCapture()) return false; auto *dc = getDeclContext(); while (!dc->isTypeContext() && !dc->isModuleScopeContext()) dc = dc->getParent(); // Check if this `self` parameter belongs to an actor declaration or // extension. auto nominal = dc->getSelfNominalTypeDecl(); return nominal && nominal->isActor(); } /// Whether the given variable is the backing storage property for /// a declared property that is either `lazy` or has an attached /// property wrapper. static bool isBackingStorageForDeclaredProperty(const VarDecl *var) { if (var->isLazyStorageProperty()) return true; if (var->getOriginalWrappedProperty()) return true; return false; } /// Whether the given variable is a declared property that has separate backing storage. static bool isDeclaredPropertyWithBackingStorage(const VarDecl *var) { if (var->getAttrs().hasAttribute()) return true; if (var->hasAttachedPropertyWrapper()) return true; return false; } bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const { // Only non-static properties in type context can be part of a memberwise // initializer. if (!getDeclContext()->isTypeContext() || isStatic()) return false; // If this is a stored property, and not a backing property in a case where // we only want to see the declared properties, it can be memberwise // initialized. if (hasStorage() && preferDeclaredProperties && isBackingStorageForDeclaredProperty(this)) return false; // If this is a computed property with `init` accessor, it's // memberwise initializable when it could be used to initialize // other stored properties. if (hasInitAccessor()) { if (auto *init = getAccessor(AccessorKind::Init)) return true; } // If this is a computed property, it's not memberwise initialized unless // the caller has asked for the declared properties and it is either a // `lazy` property or a property with an attached wrapper. if (!hasStorage() && !(preferDeclaredProperties && isDeclaredPropertyWithBackingStorage(this))) return false; // 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 (isLet() && isParentInitialized()) return false; // Properties with attached wrappers that have an access level < internal // but do have an initializer don't participate in the memberwise // initializer, because they would arbitrarily lower the access of the // memberwise initializer. auto origVar = this; if (auto origWrapped = getOriginalWrappedProperty()) origVar = origWrapped; if (origVar->getFormalAccess() < AccessLevel::Internal && origVar->hasAttachedPropertyWrapper() && (origVar->isParentInitialized() || (origVar->getParentPatternBinding() && origVar->getParentPatternBinding()->isDefaultInitializable()))) return false; return true; } bool VarDecl::isLet() const { // An awful hack that stabilizes the value of 'isLet' for ParamDecl instances. // // All of the callers in SIL are actually looking for the semantic // "is immutable" predicate (present on ParamDecl) and should be migrated to // a high-level request. Once this is done, all callers of the introducer and // specifier setters can be removed. if (auto *PD = dyn_cast(this)) { return PD->isImmutableInFunctionBody(); } return getIntroducer() == Introducer::Let || getIntroducer() == Introducer::Borrowing; } bool VarDecl::isAsyncLet() const { return getAttrs().hasAttribute(); } bool VarDecl::isKnownToBeLocal() const { return getAttrs().hasAttribute(); } bool VarDecl::isOrdinaryStoredProperty() const { // we assume if it hasAttachedPropertyWrapper, it has no storage. // // also, we don't expect someone to call this on a local property, so for // efficiency we don't check if it's not async-let. feel free to promote // the assert into a full-fledged part of the condition if needed. assert(!isAsyncLet()); return hasStorage() && !hasObservers(); } VarDecl *VarDecl::createImplicitStringInterpolationVar(DeclContext *DC) { // Make the variable which will contain our temporary value. ASTContext &C = DC->getASTContext(); auto var = new (C) VarDecl(/*IsStatic=*/false, VarDecl::Introducer::Var, /*NameLoc=*/SourceLoc(), C.Id_dollarInterpolation, DC); var->setImplicit(true); var->setUserAccessible(false); return var; } void ParamDecl::setSpecifier(Specifier specifier) { VarDecl::Introducer introducer; switch (specifier) { // Unannotated or `borrowing` parameters are locally immutable. // So are parameters using the legacy `__shared` or `__owned` modifiers. case ParamSpecifier::Default: case ParamSpecifier::Borrowing: case ParamSpecifier::LegacyShared: case ParamSpecifier::LegacyOwned: introducer = VarDecl::Introducer::Let; break; // `inout` and `consuming` parameters are locally mutable. case ParamSpecifier::InOut: case ParamSpecifier::Consuming: case ParamSpecifier::ImplicitlyCopyableConsuming: introducer = VarDecl::Introducer::Var; break; } setIntroducer(introducer); Bits.ParamDecl.OwnershipSpecifier = static_cast(specifier) + 1; assert(getCachedSpecifier() == specifier && "not enough bits in ParamDecl flags for specifier anymore!"); } bool ParamDecl::isAnonClosureParam() const { auto name = getName(); if (name.empty()) return false; auto nameStr = name.str(); if (nameStr.empty()) return false; return nameStr[0] == '$'; } bool ParamDecl::isVariadic() const { (void) getInterfaceType(); return getOptions().contains(Flag::IsVariadic); } ParamDecl::Specifier ParamDecl::getSpecifier() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ParamSpecifierRequest{mutableThis}, ParamDecl::Specifier::Default); } LifetimeAnnotation ParamDecl::getLifetimeAnnotation() const { auto specifier = getSpecifier(); // Copyable parameters which are consumed have eager-move semantics. if (specifier == ParamDecl::Specifier::Consuming && !getTypeInContext()->isNoncopyable()) { if (getAttrs().hasAttribute()) return LifetimeAnnotation::Lexical; return LifetimeAnnotation::EagerMove; } return getLifetimeAnnotationFromAttributes(); } StringRef ParamDecl::getSpecifierSpelling(ParamSpecifier specifier) { switch (specifier) { case ParamSpecifier::Default: return ""; case ParamSpecifier::Borrowing: return "borrowing"; case ParamSpecifier::Consuming: return "consuming"; case ParamSpecifier::InOut: return "inout"; case ParamSpecifier::LegacyShared: return "__shared"; case ParamSpecifier::LegacyOwned: return "__owned"; case ParamSpecifier::ImplicitlyCopyableConsuming: return "implicitly_copyable_consuming"; } llvm_unreachable("invalid ParamSpecifier"); } StaticSpellingKind AbstractStorageDecl::getCorrectStaticSpelling() const { if (!isStatic()) return StaticSpellingKind::None; if (auto *VD = dyn_cast(this)) { if (auto *PBD = VD->getParentPatternBinding()) { if (PBD->getStaticSpelling() != StaticSpellingKind::None) return PBD->getStaticSpelling(); } } else if (auto *SD = dyn_cast(this)) { return SD->getStaticSpelling(); } return getCorrectStaticSpellingForDecl(this); } llvm::TinyPtrVector VarDecl::getAttachedPropertyWrappers() const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, AttachedPropertyWrappersRequest{mutableThis}, { }); } /// Whether this property has any attached property wrappers. bool VarDecl::hasAttachedPropertyWrapper() const { if (!getAttachedPropertyWrappers().empty()) return true; if (hasImplicitPropertyWrapper()) return true; return false; } bool VarDecl::hasImplicitPropertyWrapper() const { if (getAttrs().hasAttribute()) { if (!getAttachedPropertyWrappers().empty()) return false; } if (isImplicit()) return false; if (!isa(this)) return false; if (!isa(getDeclContext())) return false; return getName().hasDollarPrefix(); } bool VarDecl::hasExternalPropertyWrapper() const { if (!hasAttachedPropertyWrapper() || !isa(this)) return false; // This decision needs to be made before closures are type checked (and // the wrapper types are potentially inferred) so closure parameters with // property wrappers are always "external". This is fine, because the // type checker will always inject a thunk with the wrapped or projected type // around the closure, so the wrapper will never affect the caller's // arguments directly anyway. if (isa(getDeclContext())) return true; // Wrappers with attribute arguments are always implementation-detail. if (getOutermostAttachedPropertyWrapper()->hasArgs()) return false; auto wrapperInfo = getAttachedPropertyWrapperTypeInfo(0); return wrapperInfo.projectedValueVar && wrapperInfo.hasProjectedValueInit; } /// Whether all of the attached property wrappers have an init(wrappedValue:) /// initializer. bool VarDecl::allAttachedPropertyWrappersHaveWrappedValueInit() const { for (unsigned i : indices(getAttachedPropertyWrappers())) { if (!getAttachedPropertyWrapperTypeInfo(i).wrappedValueInit) return false; } return true; } PropertyWrapperTypeInfo VarDecl::getAttachedPropertyWrapperTypeInfo(unsigned i) const { NominalTypeDecl *nominal; if (hasImplicitPropertyWrapper()) { assert(i == 0); nominal = getInterfaceType()->getAnyNominal(); } else { auto attrs = getAttachedPropertyWrappers(); if (i >= attrs.size()) return PropertyWrapperTypeInfo(); auto attr = attrs[i]; auto dc = getDeclContext(); ASTContext &ctx = getASTContext(); nominal = evaluateOrDefault( ctx.evaluator, CustomAttrNominalRequest{attr, dc}, nullptr); } if (!nominal) return PropertyWrapperTypeInfo(); return nominal->getPropertyWrapperTypeInfo(); } Type VarDecl::getAttachedPropertyWrapperType(unsigned index) const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, AttachedPropertyWrapperTypeRequest{mutableThis, index}, Type()); } Type VarDecl::getPropertyWrapperBackingPropertyType() const { ASTContext &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, PropertyWrapperBackingPropertyTypeRequest{mutableThis}, Type()); } PropertyWrapperAuxiliaryVariables VarDecl::getPropertyWrapperAuxiliaryVariables() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, PropertyWrapperAuxiliaryVariablesRequest{mutableThis}, PropertyWrapperAuxiliaryVariables()); } PropertyWrapperInitializerInfo VarDecl::getPropertyWrapperInitializerInfo() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, PropertyWrapperInitializerInfoRequest{mutableThis}, PropertyWrapperInitializerInfo()); } std::optional VarDecl::getPropertyWrapperMutability() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, PropertyWrapperMutabilityRequest{mutableThis}, std::nullopt); } std::optional VarDecl::getPropertyWrapperSynthesizedPropertyKind() const { if (getOriginalWrappedProperty( PropertyWrapperSynthesizedPropertyKind::Backing)) return PropertyWrapperSynthesizedPropertyKind::Backing; if (getOriginalWrappedProperty( PropertyWrapperSynthesizedPropertyKind::Projection)) return PropertyWrapperSynthesizedPropertyKind::Projection; return std::nullopt; } VarDecl *VarDecl::getPropertyWrapperBackingProperty() const { return getPropertyWrapperAuxiliaryVariables().backingVar; } VarDecl *VarDecl::getPropertyWrapperProjectionVar() const { return getPropertyWrapperAuxiliaryVariables().projectionVar; } VarDecl *VarDecl::getPropertyWrapperWrappedValueVar() const { return getPropertyWrapperAuxiliaryVariables().localWrappedValueVar; } bool VarDecl::hasStorageOrWrapsStorage() const { if (hasStorage()) return true; if (getAttrs().hasAttribute()) return true; auto *backing = getPropertyWrapperBackingProperty(); if (backing && backing->hasStorage()) return true; return false; } void VarDecl::visitAuxiliaryDecls(llvm::function_ref visit) const { if (getDeclContext()->isTypeContext() || (isImplicit() && !isa(this))) return; if (getAttrs().hasAttribute()) { if (auto *backingVar = getLazyStorageProperty()) visit(backingVar); } if (getAttrs().hasAttribute() || hasImplicitPropertyWrapper()) { if (auto *backingVar = getPropertyWrapperBackingProperty()) visit(backingVar); if (auto *projectionVar = getPropertyWrapperProjectionVar()) visit(projectionVar); if (auto *wrappedValueVar = getPropertyWrapperWrappedValueVar()) visit(wrappedValueVar); } } VarDecl *VarDecl::getLazyStorageProperty() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, LazyStoragePropertyRequest{mutableThis}, {}); } bool VarDecl::isGlobalStorage() const { if (!hasStorage()) { return false; } const auto *dc = getDeclContext(); return isStatic() || dc->isModuleScopeContext() || (dc->isTypeContext() && !isInstanceMember()); } bool VarDecl::isPropertyMemberwiseInitializedWithWrappedType() const { auto customAttrs = getAttachedPropertyWrappers(); if (customAttrs.empty()) return false; auto *PBD = getParentPatternBinding(); if (!PBD) return false; // If there was an initializer on the original property, initialize // via the initial value. if (PBD->getEqualLoc(0).isValid()) return true; // If there was an initializer on the outermost wrapper, initialize // via the full wrapper. if (customAttrs[0]->hasArgs()) return false; // Default initialization does not use a value. if (getAttachedPropertyWrapperTypeInfo(0).defaultInit) return false; // If all property wrappers have a wrappedValue initializer, the property // wrapper will be initialized that way. return allAttachedPropertyWrappersHaveWrappedValueInit(); } Type VarDecl::getPropertyWrapperInitValueInterfaceType() const { auto initInfo = getPropertyWrapperInitializerInfo(); if (!initInfo.getWrappedValuePlaceholder()) return Type(); Type valueInterfaceTy = initInfo.getWrappedValuePlaceholder()->getType(); if (valueInterfaceTy->hasPrimaryArchetype()) valueInterfaceTy = valueInterfaceTy->mapTypeOutOfContext(); return valueInterfaceTy; } Identifier VarDecl::getObjCPropertyName() const { if (auto attr = getAttrs().getAttribute()) { if (auto name = attr->getName()) return name->getSelectorPieces()[0]; } return getName(); } ObjCSelector VarDecl::getDefaultObjCGetterSelector(ASTContext &ctx, Identifier propertyName) { return ObjCSelector(ctx, 0, propertyName); } ObjCSelector VarDecl::getDefaultObjCSetterSelector(ASTContext &ctx, Identifier propertyName) { llvm::SmallString<16> scratch; scratch += "set"; camel_case::appendSentenceCase(scratch, propertyName.str()); return ObjCSelector(ctx, 1, ctx.getIdentifier(scratch)); } /// If this is a simple 'let' constant, emit a note with a fixit indicating /// that it can be rewritten to a 'var'. This is used in situations where the /// compiler detects obvious attempts to mutate a constant. void VarDecl::emitLetToVarNoteIfSimple(DeclContext *UseDC) const { // If it isn't a 'let', don't touch it. if (!isLet()) return; // If this is the 'self' argument of a non-mutating method in a value type, // suggest adding 'mutating' to the method. if (isSelfParameter() && UseDC) { // If the problematic decl is 'self', then we might be trying to mutate // a property in a non-mutating method. auto FD = dyn_cast_or_null(UseDC->getInnermostMethodContext()); if (FD && !FD->isMutating() && !FD->isImplicit() && FD->isInstanceMember()&& !FD->getDeclContext()->getDeclaredInterfaceType() ->hasReferenceSemantics()) { // Do not suggest the fix-it in implicit getters if (auto AD = dyn_cast(FD)) { if (AD->isImplicitGetter()) return; } auto &d = getASTContext().Diags; auto descriptiveKindName = Decl::getDescriptiveKindName(FD->getDescriptiveKind()); auto diags = d.diagnose(FD->getFuncLoc(), diag::change_to_mutating, isa(FD), descriptiveKindName); if (auto nonmutatingAttr = FD->getAttrs().getAttribute()) { diags.fixItReplace(nonmutatingAttr->getLocation(), "mutating"); } else { diags.fixItInsert(FD->getFuncLoc(), "mutating "); } return; } } // Besides self, don't suggest mutability for explicit function parameters. if (isa(this)) return; // Don't suggest any fixes for capture list elements. if (isCaptureList()) return; // If this is a normal variable definition, then we can change 'let' to 'var'. // We even are willing to suggest this for multi-variable binding, like // "let (a,b) = " // since the user has to choose to apply this anyway. if (auto *PBD = getParentPatternBinding()) { // Don't touch generated or invalid code. if (PBD->getLoc().isInvalid() || PBD->isImplicit()) return; auto &d = getASTContext().Diags; d.diagnose(PBD->getLoc(), diag::convert_let_to_var) .fixItReplace(PBD->getLoc(), "var"); return; } } clang::PointerAuthQualifier VarDecl::getPointerAuthQualifier() const { if (auto *clangDecl = getClangDecl()) { if (auto *valueDecl = dyn_cast(clangDecl)) { return valueDecl->getType().getPointerAuth(); } } return clang::PointerAuthQualifier(); } ParamDecl::ParamDecl(SourceLoc specifierLoc, SourceLoc argumentNameLoc, Identifier argumentName, SourceLoc parameterNameLoc, Identifier parameterName, DeclContext *dc) : VarDecl(DeclKind::Param, /*IsStatic*/ false, VarDecl::Introducer::Let, parameterNameLoc, parameterName, dc, StorageIsNotMutable), ArgumentNameAndFlags(argumentName, std::nullopt), ParameterNameLoc(parameterNameLoc), ArgumentNameLoc(argumentNameLoc), SpecifierLoc(specifierLoc) { Bits.ParamDecl.OwnershipSpecifier = 0; Bits.ParamDecl.defaultArgumentKind = static_cast(DefaultArgumentKind::None); } ParamDecl * ParamDecl::cloneWithoutType(const ASTContext &Ctx, ParamDecl *PD, std::optional defaultArgKind) { auto *Clone = new (Ctx) ParamDecl( SourceLoc(), SourceLoc(), PD->getArgumentName(), SourceLoc(), PD->getParameterName(), PD->getDeclContext()); Clone->setOptionsAndPointers(nullptr, nullptr, PD->getOptions()); if (defaultArgKind) { Clone->setDefaultArgumentKind(*defaultArgKind); } else { Clone->setDefaultArgumentKind(PD->getDefaultArgumentKind()); } Clone->setSpecifier(PD->getSpecifier()); Clone->setImplicitlyUnwrappedOptional(PD->isImplicitlyUnwrappedOptional()); if (PD->isImplicit()) { Clone->setImplicit(); } return Clone; } ParamDecl *ParamDecl::clone(const ASTContext &Ctx, ParamDecl *PD) { auto *Clone = ParamDecl::cloneWithoutType(Ctx, PD); Clone->setInterfaceType(PD->getInterfaceType()); return Clone; } ParamDecl * ParamDecl::createImplicit(ASTContext &Context, SourceLoc specifierLoc, SourceLoc argumentNameLoc, Identifier argumentName, SourceLoc parameterNameLoc, Identifier parameterName, Type interfaceType, DeclContext *Parent, ParamSpecifier specifier) { auto decl = new (Context) ParamDecl(specifierLoc, argumentNameLoc, argumentName, parameterNameLoc, parameterName, Parent); decl->setImplicit(); // implicit ParamDecls must have a specifier set decl->setSpecifier(specifier); decl->setInterfaceType(interfaceType); return decl; } ParamDecl *ParamDecl::createImplicit(ASTContext &Context, Identifier argumentName, Identifier parameterName, Type interfaceType, DeclContext *Parent, ParamSpecifier specifier) { return ParamDecl::createImplicit(Context, SourceLoc(), SourceLoc(), argumentName, SourceLoc(), parameterName, interfaceType, Parent, specifier); } /// Determine the kind of a default argument for the given expression. static DefaultArgumentKind computeDefaultArgumentKind(DeclContext *dc, Expr *init) { if (!init) return DefaultArgumentKind::None; // Parse an as-written 'nil' expression as the special NilLiteral kind, // which is emitted by the caller and can participate in rethrows // checking. if (isa(init)) return DefaultArgumentKind::NilLiteral; if (isa(init)) return DefaultArgumentKind::ExpressionMacro; if (isa(init)) { // The compiler does not synthesize inherited initializers when // type-checking Swift module interfaces. Instead, module interfaces are // expected to include them explicitly in subclasses. A default argument of // '= super' in a parameter of such initializer indicates that the default // argument is inherited. if (dc->getParentSourceFile()->Kind == SourceFileKind::Interface) { return DefaultArgumentKind::Inherited; } else { return DefaultArgumentKind::Normal; } } auto magic = dyn_cast(init); if (!magic) return DefaultArgumentKind::Normal; switch (magic->getKind()) { #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case MagicIdentifierLiteralExpr::NAME: \ return DefaultArgumentKind::NAME; #include "swift/AST/MagicIdentifierKinds.def" } llvm_unreachable("Unhandled MagicIdentifierLiteralExpr in switch."); } ParamDecl *ParamDecl::createParsed(ASTContext &Context, SourceLoc specifierLoc, SourceLoc argumentNameLoc, Identifier argumentName, SourceLoc parameterNameLoc, Identifier parameterName, Expr *defaultValue, DeclContext *dc) { auto *decl = new (Context) ParamDecl(specifierLoc, argumentNameLoc, argumentName, parameterNameLoc, parameterName, dc); const auto kind = computeDefaultArgumentKind(dc, defaultValue); if (kind == DefaultArgumentKind::Inherited) { // The 'super' in inherited default arguments is a specifier rather than an // expression. // TODO: However, we may want to retain its location for diagnostics. defaultValue = nullptr; } decl->setDefaultExpr(defaultValue); decl->setDefaultArgumentKind(kind); return decl; } void ParamDecl::setDefaultArgumentKind(DefaultArgumentKind K) { assert(getDefaultArgumentKind() == DefaultArgumentKind::None && "Overwrite of default argument kind"); Bits.ParamDecl.defaultArgumentKind = static_cast(K); } /// Retrieve the type of 'self' for the given context. Type DeclContext::getSelfTypeInContext() const { return mapTypeIntoContext(getSelfInterfaceType()); } TupleType *BuiltinTupleDecl::getTupleSelfType(const ExtensionDecl *owner) const { auto &ctx = getASTContext(); // Get the generic parameter type 'each T'. GenericParamList *genericParams; if (owner != nullptr) { genericParams = owner->getGenericParams(); } else { genericParams = getGenericParams(); } assert(genericParams != nullptr); assert(genericParams->getParams().size() == 1); assert(genericParams->getOuterParameters() == nullptr); auto paramType = genericParams->getParams()[0]->getDeclaredInterfaceType(); // Build the pack expansion type 'repeat each T'. Type packExpansionType = PackExpansionType::get(paramType, paramType); // Build the one-element tuple type '(repeat each T)'. SmallVector elts; elts.push_back(packExpansionType); return TupleType::get(elts, ctx); } /// Retrieve the interface type of 'self' for the given context. Type DeclContext::getSelfInterfaceType() const { assert(isTypeContext()); if (auto *nominalDecl = getSelfNominalTypeDecl()) { if (auto *builtinTupleDecl = dyn_cast(nominalDecl)) return builtinTupleDecl->getTupleSelfType(dyn_cast(this)); if (isa(nominalDecl)) { auto *genericParams = nominalDecl->getGenericParams(); return genericParams->getParams().front() ->getDeclaredInterfaceType(); } return getDeclaredInterfaceType(); } return ErrorType::get(getASTContext()); } /// Return the full source range of this parameter. SourceRange ParamDecl::getSourceRange() const { SourceLoc APINameLoc = getArgumentNameLoc(); SourceLoc nameLoc = getNameLoc(); SourceLoc startLoc; if (APINameLoc.isValid()) startLoc = APINameLoc; else if (nameLoc.isValid()) startLoc = nameLoc; else if (auto *repr = getTypeRepr()) startLoc = repr->getStartLoc(); if (startLoc.isInvalid()) return SourceRange(); // It would be nice to extend the front of the range to show where inout is, // but we don't have that location info. Extend the back of the range to the // location of the default argument, or the typeloc if they are valid. if (auto expr = getStructuralDefaultExpr()) { auto endLoc = expr->getEndLoc(); if (endLoc.isValid()) return SourceRange(startLoc, endLoc); } // If the typeloc has a valid location, use it to end the range. if (auto typeRepr = getTypeRepr()) { auto endLoc = typeRepr->getEndLoc(); if (endLoc.isValid()) return SourceRange(startLoc, endLoc); } // The name has a location we can use. if (nameLoc.isValid()) return SourceRange(startLoc, nameLoc); return startLoc; } bool ParamDecl::isNonEphemeral() const { if (getAttrs().hasAttribute()) return true; // Only enum element parameters are non-ephemeral without '@_nonEphemeral'. auto *parentDecl = getDeclContext()->getAsDecl(); if (!parentDecl || !isa(parentDecl)) return false; // Only pointer parameters can be non-ephemeral. auto ty = getInterfaceType(); if (!ty->lookThroughSingleOptionalType()->getAnyPointerElementType()) return false; return true; } void ParamDecl::setNonEphemeralIfPossible() { assert(hasInterfaceType() && "Must be pre-typechecked."); // Don't apply the attribute if this isn't a pointer param. auto type = getInterfaceType(); if (!type->lookThroughSingleOptionalType()->getAnyPointerElementType()) return; if (!getAttrs().hasAttribute()) { auto &ctx = getASTContext(); getAttrs().add(new (ctx) NonEphemeralAttr(/*IsImplicit*/ true)); } } Type ParamDecl::getVarargBaseTy(Type VarArgT) { TypeBase *T = VarArgT.getPointer(); if (auto *AT = dyn_cast(T)) return AT->getBaseType(); if (auto *BGT = dyn_cast(T)) { // It's the stdlib Array. return BGT->getGenericArgs()[0]; } return T; } AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const { if (!type) { type = getInterfaceType(); if (hasExternalPropertyWrapper()) { if (auto wrapper = getPropertyWrapperBackingPropertyType()) { type = wrapper; } } } if (isVariadic()) type = ParamDecl::getVarargBaseTy(type); auto label = getArgumentName(); auto internalLabel = getParameterName(); auto flags = ParameterTypeFlags::fromParameterType( type, isVariadic(), isAutoClosure(), isNonEphemeral(), getSpecifier(), isIsolated(), /*isNoDerivative*/ false, isCompileTimeConst(), isSending()); return AnyFunctionType::Param(type, label, flags, internalLabel); } std::optional ParamDecl::getCachedDefaultArgumentInitContext() const { if (auto *defaultInfo = DefaultValueAndFlags.getPointer()) if (auto *init = defaultInfo->InitContextAndIsTypeChecked.getPointer()) return init; return std::nullopt; } Initializer *ParamDecl::getDefaultArgumentInitContext() const { // If this param doesn't need a context, don't bother kicking off a request. if (!hasDefaultExpr() && !getStoredProperty()) return nullptr; auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, DefaultArgumentInitContextRequest{mutableThis}, nullptr); } bool ParamDecl::hasDefaultExpr() const { switch (getDefaultArgumentKind()) { case DefaultArgumentKind::None: case DefaultArgumentKind::Inherited: case DefaultArgumentKind::StoredProperty: return false; case DefaultArgumentKind::Normal: #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case DefaultArgumentKind::NAME: #include "swift/AST/MagicIdentifierKinds.def" case DefaultArgumentKind::ExpressionMacro: case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: // Check if we have a structural default expr. This ensures we return false // for deserialized decls. return getStructuralDefaultExpr(); } llvm_unreachable("Unhandled case in switch"); } bool ParamDecl::hasCallerSideDefaultExpr() const { switch (getDefaultArgumentKind()) { case DefaultArgumentKind::None: case DefaultArgumentKind::Inherited: case DefaultArgumentKind::StoredProperty: case DefaultArgumentKind::Normal: return false; #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case DefaultArgumentKind::NAME: #include "swift/AST/MagicIdentifierKinds.def" case DefaultArgumentKind::NilLiteral: case DefaultArgumentKind::EmptyArray: case DefaultArgumentKind::EmptyDictionary: case DefaultArgumentKind::ExpressionMacro: return true; } llvm_unreachable("invalid default argument kind"); } Expr *ParamDecl::getTypeCheckedDefaultExpr() const { // Don't kick off a request if we know there's no default expr. The only // exception is for inherited default args which we need to perform a couple // of semantic checks for. if (!hasDefaultExpr() && getDefaultArgumentKind() != DefaultArgumentKind::Inherited) { return nullptr; } auto &ctx = getASTContext(); if (Expr *E = evaluateOrDefault( ctx.evaluator, DefaultArgumentExprRequest{const_cast(this)}, nullptr)) { return E; } return new (ctx) ErrorExpr(getSourceRange(), ErrorType::get(ctx)); } Type ParamDecl::getTypeOfDefaultExpr() const { auto &ctx = getASTContext(); // If this is a caller-side default, the type is determined based on // a particular call site. assert(!hasCallerSideDefaultExpr()); if (Type type = evaluateOrDefault( ctx.evaluator, DefaultArgumentTypeRequest{const_cast(this)}, nullptr)) { return type; } return Type(); } void ParamDecl::setDefaultExpr(Expr *E) { auto *defaultInfo = DefaultValueAndFlags.getPointer(); if (defaultInfo) { assert(defaultInfo->DefaultArg.isNull() || defaultInfo->DefaultArg.is()); auto *const oldE = defaultInfo->DefaultArg.dyn_cast(); assert((bool)E == (bool)oldE && "Overwrite of non-null default with null"); assert((!oldE || !oldE->getType() || (bool)E->getType()) && "Overwrite of type-checked default with non-type-checked default"); } else { if (!E) return; defaultInfo = getASTContext().Allocate(); DefaultValueAndFlags.setPointer(defaultInfo); defaultInfo->InitContextAndIsTypeChecked.setInt(false); } defaultInfo->DefaultArg = E; } void ParamDecl::setTypeCheckedDefaultExpr(Expr *E) { assert(E || getDefaultArgumentKind() == DefaultArgumentKind::Inherited); setDefaultExpr(E); auto *defaultInfo = DefaultValueAndFlags.getPointer(); if (!defaultInfo) { defaultInfo = getASTContext().Allocate(); DefaultValueAndFlags.setPointer(defaultInfo); } defaultInfo->InitContextAndIsTypeChecked.setInt(true); } void ParamDecl::setDefaultExprType(Type type) { if (!DefaultValueAndFlags.getPointer()) { // If there is no type, let's not allocate storage. if (!type) return; DefaultValueAndFlags.setPointer( getASTContext().Allocate()); } auto *defaultInfo = DefaultValueAndFlags.getPointer(); defaultInfo->ExprType = type; } void ParamDecl::setStoredProperty(VarDecl *var) { if (!DefaultValueAndFlags.getPointer()) { if (!var) return; DefaultValueAndFlags.setPointer( getASTContext().Allocate()); } auto *defaultInfo = DefaultValueAndFlags.getPointer(); assert(defaultInfo->DefaultArg.isNull() || defaultInfo->DefaultArg.is()); defaultInfo->DefaultArg = var; } Type ValueDecl::getResultBuilderType() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ResultBuilderTypeRequest{mutableThis}, Type()); } CustomAttr *ValueDecl::getAttachedResultBuilder() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, AttachedResultBuilderRequest{mutableThis}, nullptr); } void ParamDecl::setDefaultArgumentInitContext(Initializer *initContext) { auto oldContext = getCachedDefaultArgumentInitContext(); assert((!oldContext || oldContext == initContext) && "Cannot change init context after setting"); auto *defaultInfo = DefaultValueAndFlags.getPointer(); assert(defaultInfo); defaultInfo->InitContextAndIsTypeChecked.setPointer(initContext); } CaptureInfo ParamDecl::getDefaultArgumentCaptureInfo() const { if (!DefaultValueAndFlags.getPointer()) return CaptureInfo::empty(); auto &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, ParamCaptureInfoRequest{const_cast(this)}, CaptureInfo::empty()); } void ParamDecl::setDefaultArgumentCaptureInfo(CaptureInfo captures) { assert(DefaultValueAndFlags.getPointer()); assert(captures.hasBeenComputed()); DefaultValueAndFlags.getPointer()->Captures = captures; } PropertyWrapperValuePlaceholderExpr * swift::findWrappedValuePlaceholder(Expr *init) { class Walker : public ASTWalker { public: PropertyWrapperValuePlaceholderExpr *placeholder = nullptr; /// Only walk the arguments of a macro, to represent the source as written. MacroWalking getMacroWalkingBehavior() const override { return MacroWalking::Arguments; } virtual PreWalkResult walkToExprPre(Expr *E) override { if (placeholder) return Action::SkipNode(E); if (auto *value = dyn_cast(E)) { placeholder = value; return Action::SkipNode(value); } return Action::Continue(E); } } walker; init->walk(walker); return walker.placeholder; } /// Writes a tuple expression where each element is either `nil` or another such /// tuple of nils. /// This comes up when printing default arguments for memberwise initializers /// that were created implicitly. /// For example, this var: /// ``` /// var x: (Int?, (Int?, Int?, ())) /// ``` /// will produce `(nil, (nil, nil, ()))` static void writeTupleOfNils(TupleType *type, llvm::raw_ostream &os) { os << '('; for (unsigned i = 0; i < type->getNumElements(); ++i) { auto &elt = type->getElement(i); if (elt.hasName()) { os << elt.getName().str() << ": "; } if (elt.getType()->getOptionalObjectType()) { os << "nil"; } else { writeTupleOfNils(elt.getType()->castTo(), os); } if (i < type->getNumElements() - 1) { os << ", "; } } os << ')'; } /// Determines if the given type is a potentially nested tuple of optional /// types. static bool isTupleOfOptionals(Type type) { auto tuple = type->getAs(); if (!tuple) return false; for (auto elt : tuple->getElementTypes()) if (!elt->getOptionalObjectType() && !isTupleOfOptionals(elt)) return false; return true; } StringRef ParamDecl::getDefaultValueStringRepresentation( SmallVectorImpl &scratch) const { switch (getDefaultArgumentKind()) { case DefaultArgumentKind::None: llvm_unreachable("called on a ParamDecl with no default value"); case DefaultArgumentKind::ExpressionMacro: case DefaultArgumentKind::Normal: { assert(DefaultValueAndFlags.getPointer() && "default value not provided yet"); auto existing = DefaultValueAndFlags.getPointer()->StringRepresentation; if (!existing.empty()) return existing; assert(hasDefaultExpr() && "Normal default argument with no default expression?!"); return extractInlinableText(getASTContext(), getStructuralDefaultExpr(), scratch); } case DefaultArgumentKind::StoredProperty: { assert(DefaultValueAndFlags.getPointer() && "default value not provided yet"); auto existing = DefaultValueAndFlags.getPointer()->StringRepresentation; if (!existing.empty()) return existing; auto var = getStoredProperty(); if (auto original = var->getOriginalWrappedProperty()) { auto wrapperAttrs = original->getAttachedPropertyWrappers(); if (wrapperAttrs.size() > 0) { auto attr = wrapperAttrs.front(); if (auto *args = attr->getArgs()) { SourceRange fullRange(attr->getTypeRepr()->getSourceRange().Start, args->getEndLoc()); auto charRange = Lexer::getCharSourceRangeFromSourceRange( getASTContext().SourceMgr, fullRange); return getASTContext().SourceMgr.extractText(charRange); } // If there is no initial wrapped value, we used the default initializer. Expr *wrappedValue = nullptr; if (auto *parentInit = original->getParentInitializer()) if (auto *placeholder = findWrappedValuePlaceholder(parentInit)) wrappedValue = placeholder->getOriginalWrappedValue(); if (!wrappedValue) { if (auto type = original->getPropertyWrapperBackingPropertyType()) { if (auto nominal = type->getAnyNominal()) { scratch.clear(); auto typeName = nominal->getName().str(); scratch.append(typeName.begin(), typeName.end()); scratch.push_back('('); scratch.push_back(')'); return {scratch.data(), scratch.size()}; } } return ".init()"; } return extractInlinableText(getASTContext(), wrappedValue, scratch); } } auto init = var->getParentInitializer(); if (!init || !init->getSourceRange().isValid()) { // Special case: There are two possible times where we will synthesize a // default initial value for a stored property: if the type // is Optional, or if it's a (potentially nested) tuple of // all Optional elements. If it's Optional, we'll set // the DefaultArgumentKind to NilLiteral, but if we're still // handling a StoredProperty, then we know it's a tuple. if (isTupleOfOptionals(getInterfaceType())) { llvm::raw_svector_ostream os(scratch); writeTupleOfNils(getInterfaceType()->castTo(), os); return os.str(); } return "<>"; } return extractInlinableText(getASTContext(), init, scratch); } case DefaultArgumentKind::Inherited: return "super"; #define MAGIC_IDENTIFIER(NAME, STRING, SYNTAX_KIND) \ case DefaultArgumentKind::NAME: return STRING; #include "swift/AST/MagicIdentifierKinds.def" case DefaultArgumentKind::NilLiteral: return "nil"; case DefaultArgumentKind::EmptyArray: return "[]"; case DefaultArgumentKind::EmptyDictionary: return "[:]"; } llvm_unreachable("unhandled kind"); } void ParamDecl::setDefaultValueStringRepresentation(StringRef stringRepresentation) { assert(getDefaultArgumentKind() == DefaultArgumentKind::Normal || getDefaultArgumentKind() == DefaultArgumentKind::StoredProperty || getDefaultArgumentKind() == DefaultArgumentKind::ExpressionMacro); assert(!stringRepresentation.empty()); if (!DefaultValueAndFlags.getPointer()) { DefaultValueAndFlags.setPointer( getASTContext().Allocate()); } DefaultValueAndFlags.getPointer()->StringRepresentation = stringRepresentation; } void DefaultArgumentInitializer::changeFunction( DeclContext *parent, ParameterList *paramList) { if (parent->isLocalContext()) { setParent(parent); } auto param = paramList->get(getIndex()); if (param->hasDefaultExpr() || param->getStoredProperty()) param->setDefaultArgumentInitContext(this); } /// Determine whether the given Swift type is an integral type, i.e., /// a type that wraps a builtin integer. static bool isIntegralType(Type type) { // Consider structs in the standard library module that wrap a builtin // integer type to be integral types. if (auto structTy = type->getAs()) { auto structDecl = structTy->getDecl(); const DeclContext *DC = structDecl->getDeclContext(); if (!DC->isModuleScopeContext() || !DC->getParentModule()->isStdlibModule()) return false; // Find the single ivar. VarDecl *singleVar = nullptr; for (auto member : structDecl->getStoredProperties()) { if (singleVar) return false; singleVar = member; } if (!singleVar) return false; // Check whether it has integer type. return singleVar->getInterfaceType()->is(); } return false; } void SubscriptDecl::setIndices(ParameterList *p) { Indices = p; if (Indices) Indices->setDeclContextOfParamDecls(this); } Type SubscriptDecl::getElementInterfaceType() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); if (auto type = evaluateOrDefault(ctx.evaluator, ResultTypeRequest{mutableThis}, Type())) return type; return ErrorType::get(ctx); } ObjCSubscriptKind SubscriptDecl::getObjCSubscriptKind() const { // If the index type is an integral type, we have an indexed // subscript. if (auto funcTy = getInterfaceType()->getAs()) { auto params = funcTy->getParams(); if (params.size() == 1) if (isIntegralType(params[0].getPlainType())) return ObjCSubscriptKind::Indexed; } // If the index type is an object type in Objective-C, we have a // keyed subscript. return ObjCSubscriptKind::Keyed; } void SubscriptDecl::setElementInterfaceType(Type type) { getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, std::move(type)); } SubscriptDecl * SubscriptDecl::createDeserialized(ASTContext &Context, DeclName Name, StaticSpellingKind StaticSpelling, Type ElementTy, DeclContext *Parent, GenericParamList *GenericParams) { assert(ElementTy && "Deserialized element type must not be null"); auto *const SD = new (Context) SubscriptDecl(Name, SourceLoc(), StaticSpelling, SourceLoc(), nullptr, SourceLoc(), /*ElementTyR=*/nullptr, Parent, GenericParams); SD->setElementInterfaceType(ElementTy); return SD; } SubscriptDecl *SubscriptDecl::createParsed( ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, SourceLoc ArrowLoc, TypeRepr *ElementTyR, DeclContext *Parent, GenericParamList *GenericParams) { assert(ElementTyR); auto Name = DeclName(Context, DeclBaseName::createSubscript(), Indices); auto *const SD = new (Context) SubscriptDecl(Name, StaticLoc, StaticSpelling, SubscriptLoc, Indices, ArrowLoc, ElementTyR, Parent, GenericParams); return SD; } SubscriptDecl *SubscriptDecl::create(ASTContext &Context, DeclName Name, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc SubscriptLoc, ParameterList *Indices, SourceLoc ArrowLoc, Type ElementTy, DeclContext *Parent, GenericParamList *GenericParams) { auto *const SD = new (Context) SubscriptDecl(Name, StaticLoc, StaticSpelling, SubscriptLoc, Indices, ArrowLoc, nullptr, Parent, GenericParams); SD->setElementInterfaceType(ElementTy); return SD; } SubscriptDecl *SubscriptDecl::createImported(ASTContext &Context, DeclName Name, SourceLoc SubscriptLoc, ParameterList *Indices, SourceLoc ArrowLoc, Type ElementTy, DeclContext *Parent, GenericParamList *GenericParams, ClangNode ClangN) { assert(ClangN && ElementTy); auto *DeclPtr = allocateMemoryForDecl( Context, sizeof(SubscriptDecl), /*includeSpaceForClangNode=*/true); auto *const SD = ::new (DeclPtr) SubscriptDecl(Name, SourceLoc(), StaticSpellingKind::None, SubscriptLoc, Indices, ArrowLoc, /*ElementTyR=*/nullptr, Parent, GenericParams); SD->setElementInterfaceType(ElementTy); SD->setClangNode(ClangN); return SD; } SourceRange SubscriptDecl::getSourceRange() const { auto Start = getStaticLoc().isValid() ? getStaticLoc() : getSubscriptLoc(); if (Start.isInvalid()) return SourceRange(); if (auto End = getBracesRange().End) return SourceRange(Start, End); if (auto *Where = getTrailingWhereClause()) { if (auto End = Where->getSourceRange().End) return SourceRange(Start, End); } if (auto *ElementTy = getElementTypeRepr()) { if (auto End = ElementTy->getEndLoc()) return SourceRange(Start, End); } if (ArrowLoc) return SourceRange(Start, ArrowLoc); if (auto *Indices = getIndices()) { if (auto End = Indices->getEndLoc()) return SourceRange(Start, End); } return SourceRange(Start); } SourceRange SubscriptDecl::getSignatureSourceRange() const { if (isImplicit()) return SourceRange(); if (auto Indices = getIndices()) { auto End = Indices->getEndLoc(); if (End.isValid()) { return SourceRange(getSubscriptLoc(), End); } } return getSubscriptLoc(); } DeclName AbstractFunctionDecl::getEffectiveFullName() const { if (getName()) return getName(); if (auto accessor = dyn_cast(this)) { auto &ctx = getASTContext(); auto storage = accessor->getStorage(); auto subscript = dyn_cast(storage); switch (accessor->getAccessorKind()) { // These don't have any extra implicit parameters. case AccessorKind::Address: case AccessorKind::MutableAddress: case AccessorKind::Get: case AccessorKind::DistributedGet: case AccessorKind::Read: case AccessorKind::Read2: case AccessorKind::Modify: case AccessorKind::Modify2: return subscript ? subscript->getName() : DeclName(ctx, storage->getBaseName(), ArrayRef()); case AccessorKind::Set: case AccessorKind::DidSet: case AccessorKind::WillSet: case AccessorKind::Init: { SmallVector argNames; // The implicit value/buffer parameter. argNames.push_back(Identifier()); // The subscript index parameters. if (subscript) { argNames.append(subscript->getName().getArgumentNames().begin(), subscript->getName().getArgumentNames().end()); } return DeclName(ctx, storage->getBaseName(), argNames); } } llvm_unreachable("bad accessor kind"); } return DeclName(); } ParameterList *swift::getParameterList(ValueDecl *source) { if (auto *AFD = dyn_cast(source)) { return AFD->getParameters(); } else if (auto *EED = dyn_cast(source)) { return EED->getParameterList(); } else if (auto *SD = dyn_cast(source)) { return SD->getIndices(); } else if (auto *MD = dyn_cast(source)) { return MD->parameterList; } return nullptr; } ParameterList *swift::getParameterList(DeclContext *source) { if (auto *D = source->getAsDecl()) { if (auto *VD = dyn_cast(D)) { return getParameterList(VD); } } else if (auto *CE = dyn_cast(source)) { return CE->getParameters(); } return nullptr; } const ParamDecl *swift::getParameterAt(ConcreteDeclRef declRef, unsigned index) { auto *source = declRef.getDecl(); if (auto *params = getParameterList(const_cast(source))) { unsigned origIndex = params->getOrigParamIndex(declRef.getSubstitutions(), index); return params->get(origIndex); } return nullptr; } const ParamDecl *swift::getParameterAt(const ValueDecl *source, unsigned index) { if (auto *params = getParameterList(const_cast(source))) { return index < params->size() ? params->get(index) : nullptr; } return nullptr; } const ParamDecl *swift::getParameterAt(const DeclContext *source, unsigned index) { if (auto *params = getParameterList(const_cast(source))) { return index < params->size() ? params->get(index) : nullptr; } return nullptr; } CaptureInfo AbstractFunctionDecl::getCaptureInfo() const { auto &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, CaptureInfoRequest{const_cast(this)}, CaptureInfo::empty()); } Type AbstractFunctionDecl::getMethodInterfaceType() const { assert(getDeclContext()->isTypeContext()); auto Ty = getInterfaceType(); if (Ty->is()) return Ty; return Ty->castTo()->getResult(); } bool AbstractFunctionDecl::hasDynamicSelfResult() const { if (auto *funcDecl = dyn_cast(this)) return funcDecl->getResultInterfaceType()->hasDynamicSelfType(); return isa(this); } AbstractFunctionDecl *AbstractFunctionDecl::getAsyncAlternative() const { // Async functions can't have async alternatives if (hasAsync()) return nullptr; const AvailableAttr *avAttr = nullptr; for (const auto *attr : getAttrs().getAttributes()) { // If there's an attribute with an already-resolved rename decl, use it if (attr->RenameDecl) { avAttr = attr; break; } // Otherwise prefer the first availability attribute with no platform and // rename parameter, falling back to the first with a rename. Note that // `getAttrs` is in reverse source order, so the last attribute is the // first in source if (!attr->Rename.empty() && (attr->Platform == PlatformKind::none || !avAttr) && !attr->isNoAsync()) { avAttr = attr; } } auto *renamedDecl = evaluateOrDefault( getASTContext().evaluator, RenamedDeclRequest{this, avAttr}, nullptr); auto *alternative = dyn_cast_or_null(renamedDecl); if (!alternative || !alternative->hasAsync()) return nullptr; return alternative; } static bool isPotentialCompletionHandler(const ParamDecl *param) { if (!param->getInterfaceType()) return false; auto *paramType = param->getInterfaceType()->getAs(); return paramType && paramType->getResult()->isVoid() && !paramType->isNoEscape() && !param->isAutoClosure(); } std::optional AbstractFunctionDecl::findPotentialCompletionHandlerParam( const AbstractFunctionDecl *asyncAlternative) const { const ParameterList *params = getParameters(); if (params->size() == 0) return std::nullopt; // If no async alternative given, just find the last parameter that matches // a completion handler signature if (!asyncAlternative) { for (int i = params->size() - 1; i >= 0; --i) { if (isPotentialCompletionHandler(params->get(i))) return i; } return std::nullopt; } // If this is an imported function with an async convention then we already // have the index, grab it from there auto asyncConvention = asyncAlternative->getForeignAsyncConvention(); if (asyncConvention) { auto errorConvention = asyncAlternative->getForeignErrorConvention(); unsigned handlerIndex = asyncConvention->completionHandlerParamIndex(); if (errorConvention && !errorConvention->isErrorParameterReplacedWithVoid() && handlerIndex >= errorConvention->getErrorParameterIndex()) { handlerIndex--; } return handlerIndex; } // Otherwise, match up the parameters of each function and return the single // missing parameter that must also match a completion handler signature. // Ignore any defaulted params in the alternative if their label is different // to the corresponding param in the original function. const ParameterList *asyncParams = asyncAlternative->getParameters(); unsigned paramIndex = 0; unsigned asyncParamIndex = 0; std::optional potentialParam; while (paramIndex < params->size() || asyncParamIndex < asyncParams->size()) { if (paramIndex >= params->size()) { // Have more async params than original params, if we haven't found a // completion handler then there isn't going to be any. If we have then // ensure the rest of the async params are defaulted if (!potentialParam || !asyncParams->get(asyncParamIndex)->isDefaultArgument()) return std::nullopt; asyncParamIndex++; continue; } auto *param = params->get(paramIndex); bool paramMatches = false; if (asyncParamIndex < asyncParams->size()) { const ParamDecl *asyncParam = asyncParams->get(asyncParamIndex); // Skip if the labels are different and it's defaulted if (param->getArgumentName() != asyncParam->getArgumentName() && asyncParam->isDefaultArgument()) { asyncParamIndex++; continue; } // Don't have types for some reason, just return no match if (!param->getInterfaceType() || !asyncParam->getInterfaceType()) return std::nullopt; paramMatches = param->getInterfaceType()->matchesParameter( asyncParam->getInterfaceType(), TypeMatchOptions()); } if (paramMatches) { paramIndex++; asyncParamIndex++; continue; } // Param doesn't match, either it's the first completion handler or these // functions don't match if (potentialParam || !isPotentialCompletionHandler(param)) return std::nullopt; // The next original param should match the current async, so don't // increment the async index potentialParam = paramIndex; paramIndex++; } return potentialParam; } bool AbstractFunctionDecl::argumentNameIsAPIByDefault() const { // Initializers have argument labels. if (isa(this)) return true; if (auto func = dyn_cast(this)) { // Operators do not have argument labels. if (func->isOperator()) return false; // Other functions have argument labels for all arguments return true; } assert(isa(this)); return false; } bool AbstractFunctionDecl::isSendable() const { return getAttrs().hasAttribute(); } bool AbstractFunctionDecl::hasBody() const { switch (getBodyKind()) { case BodyKind::Deserialized: case BodyKind::Parsed: case BodyKind::SILSynthesize: case BodyKind::Synthesize: case BodyKind::Unparsed: return true; case BodyKind::None: return false; case BodyKind::TypeChecked: return BodyAndFP.getBody() != nullptr; } } bool AbstractFunctionDecl::bodyHasExplicitReturnStmt() const { return AnyFunctionRef(const_cast(this)) .bodyHasExplicitReturnStmt(); } void AbstractFunctionDecl::getExplicitReturnStmts( SmallVectorImpl &results) const { AnyFunctionRef(const_cast(this)) .getExplicitReturnStmts(results); } /// Expand all preamble macros attached to the given function declaration. static std::vector expandPreamble(AbstractFunctionDecl *func) { std::vector preamble; ASTContext &ctx = func->getASTContext(); ExpandPreambleMacroRequest request{func}; auto module = func->getParentModule(); for (auto bufferID : evaluateOrDefault(ctx.evaluator, request, { })) { auto bufferStart = ctx.SourceMgr.getLocForBufferStart(bufferID); auto preambleSF = module->getSourceFileContainingLocation(bufferStart); preamble.insert(preamble.end(), preambleSF->getTopLevelItems().begin(), preambleSF->getTopLevelItems().end()); } return preamble; } /// Expand body macros and produce the resulting body. static BraceStmt *expandBodyMacro(AbstractFunctionDecl *fn) { ASTContext &ctx = fn->getASTContext(); // Expand a body macro, if there is one. BraceStmt *macroExpandedBody = nullptr; if (auto bufferID = evaluateOrDefault( ctx.evaluator, ExpandBodyMacroRequest{fn}, std::nullopt)) { CharSourceRange bufferRange = ctx.SourceMgr.getRangeForBuffer(*bufferID); auto bufferStart = bufferRange.getStart(); auto module = fn->getParentModule(); auto macroSourceFile = module->getSourceFileContainingLocation(bufferStart); if (macroSourceFile->getTopLevelItems().size() == 1) { auto stmt = macroSourceFile->getTopLevelItems()[0].dyn_cast(); macroExpandedBody = dyn_cast(stmt); } } // Expand the preamble. auto preamble = expandPreamble(fn); // If there is no preamble, we're done one way or the other: return the // macro-expanded body. if (preamble.empty()) return macroExpandedBody; // We have a preamble. The body is either the one produced by macro expansion, // or if not that, the one that was written. auto body = macroExpandedBody ? macroExpandedBody : fn->getBody(); // If there is no body at this point, the preamble has nowhere to go. if (!body) { // FIXME: diagnose this return nullptr; } // Merge the preamble into the body. auto contents = std::move(preamble); contents.insert( contents.end(), body->getElements().begin(), body->getElements().end()); return BraceStmt::create( ctx, body->getStartLoc(), contents, body->getEndLoc()); } BraceStmt *AbstractFunctionDecl::getMacroExpandedBody() const { auto mutableThis = const_cast(this); switch (getBodyKind()) { case BodyKind::None: case BodyKind::Unparsed: case BodyKind::Parsed: switch (getBodyExpandedStatus()) { case BodyExpandedStatus::NotExpanded: if (auto expandedBody = expandBodyMacro(mutableThis)) { // Save the original body's source range. mutableThis->keepOriginalBodySourceRange(); // Cache the expanded macro body as the parsed body of the function. mutableThis->setBodyExpandedStatus(BodyExpandedStatus::Expanded); mutableThis->setBodyParsed(expandedBody); return expandedBody; } mutableThis->setBodyExpandedStatus(BodyExpandedStatus::NoMacros); break; case BodyExpandedStatus::NoMacros: case BodyExpandedStatus::Expanded: break; } // Fall through to get the body. LLVM_FALLTHROUGH; case BodyKind::Synthesize: case BodyKind::TypeChecked: case BodyKind::SILSynthesize: case BodyKind::Deserialized: return getBody(/*canSynthesize=*/true); } } BraceStmt *AbstractFunctionDecl::getBody(bool canSynthesize) const { if ((getBodyKind() == BodyKind::Synthesize || getBodyKind() == BodyKind::Unparsed) && !canSynthesize) return nullptr; ASTContext &ctx = getASTContext(); // Don't allow getBody() to trigger parsing of an unparsed body containing the // IDE inspection location. // FIXME: We should be properly constructing the range of the body as a // CharSourceRange but we can't because we don't have access to the lexer // here. Using the end location of the SourceRange works good enough here // because the last token is a '}' and the IDE inspection point is not inside // the closing brace. if (getBodyKind() == BodyKind::Unparsed && ctx.SourceMgr.rangeContainsIDEInspectionTarget( CharSourceRange(ctx.SourceMgr, getBodySourceRange().Start, getBodySourceRange().End))) { return nullptr; } auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ParseAbstractFunctionBodyRequest{mutableThis}, {}) .getBody(); } BraceStmt *AbstractFunctionDecl::getTypecheckedBody() const { auto &ctx = getASTContext(); auto *mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, TypeCheckFunctionBodyRequest{mutableThis}, nullptr); } void AbstractFunctionDecl::setBody(BraceStmt *S, BodyKind NewBodyKind) { std::optional fp = std::nullopt; if (getBodyKind() == BodyKind::TypeChecked || getBodyKind() == BodyKind::Parsed) { fp = BodyAndFP.getFingerprint(); } BodyAndFP = BodyAndFingerprint(S, fp); setBodyKind(NewBodyKind); // Need to recompute init body kind. if (NewBodyKind < BodyKind::TypeChecked) { if (auto *ctor = dyn_cast(this)) ctor->clearCachedDelegatingOrChainedInitKind(); } } bool AbstractFunctionDecl::isBodySkipped() const { return evaluateOrDefault(getASTContext().evaluator, IsFunctionBodySkippedRequest{this}, false); } /// Determines whether typechecking can be skipped for a function body. Bodies /// are skipped as a performance optimization when an /// `-experimental-skip-*-function-bodies` flag is specified and the body meets /// the criteria for skipping. If a body is skipped during typechecking, it is /// also skipped during SILGen. Some bodies cannot be skipped, even when they /// otherwise meet the criteria, because typechecking them has essential /// side-effects that are required for correctness of the AST. bool IsFunctionBodySkippedRequest::evaluate( Evaluator &evaluator, const AbstractFunctionDecl *afd) const { auto &Ctx = afd->getASTContext(); auto skippingMode = Ctx.TypeCheckerOpts.SkipFunctionBodies; if (skippingMode == FunctionBodySkipping::None) return false; // Functions that have been synthesized for clang modules will be serialized // because they have shared linkage. if (isa(afd->getDeclContext()->getModuleScopeContext())) return false; if (auto *accessor = dyn_cast(afd)) { // didSet accessors needs to be checked to determine whether to keep their // parameters. if (accessor->getAccessorKind() == AccessorKind::DidSet) return false; // Synthesized accessors with forced static dispatch are emitted on-demand // and are serialized. Since they are serialized we must be willing to // typecheck them. if (accessor->hasForcedStaticDispatch()) return false; } // Actor initializers need to be checked to determine delegation status. if (auto *ctor = dyn_cast(afd)) if (auto *nom = ctor->getParent()->getSelfNominalTypeDecl()) if (nom->isAnyActor()) return false; // Skipping all bodies won't serialize anything, so we can skip everything // else. if (skippingMode == FunctionBodySkipping::All) return true; // If we want all types (for LLDB) then we can't skip functions with nested // types. We could probably improve upon this and type-check only the nested // types instead for better performances. if (afd->hasNestedTypeDeclarations() && skippingMode == FunctionBodySkipping::NonInlinableWithoutTypes) return false; // Skip functions that don't need to be serialized. return afd->getResilienceExpansion() != ResilienceExpansion::Minimal; } void AbstractFunctionDecl::setBodyToBeReparsed(SourceRange bodyRange) { assert(bodyRange.isValid()); assert(getBodyKind() == BodyKind::Unparsed || getBodyKind() == BodyKind::Parsed || getBodyKind() == BodyKind::TypeChecked); keepOriginalBodySourceRange(); BodyRange = bodyRange; setBodyKind(BodyKind::Unparsed); if (auto SF = getParentSourceFile()) { SF->getASTContext().evaluator.clearCachedOutput(LocalTypeDeclsRequest{SF}); } } SourceRange AbstractFunctionDecl::getBodySourceRange() const { switch (getBodyKind()) { case BodyKind::None: case BodyKind::SILSynthesize: case BodyKind::Deserialized: case BodyKind::Synthesize: return SourceRange(); case BodyKind::Parsed: case BodyKind::TypeChecked: if (auto body = getBody(/*canSynthesize=*/false)) return body->getSourceRange(); return SourceRange(); case BodyKind::Unparsed: return BodyRange; } llvm_unreachable("bad BodyKind"); } SourceRange AbstractFunctionDecl::getSignatureSourceRange() const { if (isImplicit()) return SourceRange(); auto paramList = getParameters(); auto endLoc = paramList->getSourceRange().End; if (endLoc.isValid()) return SourceRange(getNameLoc(), endLoc); return getNameLoc(); } std::optional AbstractFunctionDecl::getBodyFingerprint() const { ASTContext &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault(ctx.evaluator, ParseAbstractFunctionBodyRequest{mutableThis}, {}) .getFingerprint(); } std::optional AbstractFunctionDecl::getBodyFingerprintIncludingLocalTypeMembers() const { class HashCombiner : public ASTWalker { StableHasher &hasher; public: HashCombiner(StableHasher &hasher) : hasher(hasher) {} /// Only walk the arguments of a macro, to represent the source as written. MacroWalking getMacroWalkingBehavior() const override { return MacroWalking::Arguments; } PreWalkAction walkToDeclPre(Decl *D) override { if (D->isImplicit()) return Action::SkipNode(); if (auto *idc = dyn_cast(D)) { if (auto fp = idc->getBodyFingerprint()) hasher.combine(*fp); // Since ASTWalker calls 'getMembers()' which might tries to synthesize // members etc., manually recurse into `getParsedMembers()`. for (auto *d : idc->getParsedMembers()) const_cast(d)->walk(*this); return Action::SkipNode(); } if (auto *afd = dyn_cast(D)) { if (auto fp = afd->getBodyFingerprint()) hasher.combine(*fp); } return Action::Continue(); } }; StableHasher hasher = StableHasher::defaultHasher(); HashCombiner combiner(hasher); const_cast(this)->walk(combiner); return Fingerprint(std::move(hasher)); } ObjCSelector AbstractFunctionDecl::getObjCSelector(DeclName preferredName, bool skipIsObjCResolution) const { // FIXME: Forces computation of the Objective-C selector. if (!skipIsObjCResolution) (void)isObjC(); // If there is an @objc attribute with a name, use that name. auto *objc = getAttrs().getAttribute(); if (auto name = getNameFromObjcAttribute(objc, preferredName)) { return *name; } auto &ctx = getASTContext(); StringRef baseNameStr; if (auto destructor = dyn_cast(this)) { return destructor->getObjCSelector(); } else if (auto func = dyn_cast(this)) { // Otherwise cast this to be able to access getName() baseNameStr = func->getBaseIdentifier().str(); } else if (isa(this)) { baseNameStr = "init"; } else { llvm_unreachable("Unknown subclass of AbstractFunctionDecl"); } auto argNames = getName().getArgumentNames(); // Use the preferred name if specified if (preferredName) { // Return invalid selector if argument count doesn't match. if (argNames.size() != preferredName.getArgumentNames().size()) { return ObjCSelector(); } baseNameStr = preferredName.getBaseName().userFacingName(); argNames = preferredName.getArgumentNames(); } auto baseName = ctx.getIdentifier(baseNameStr); if (auto accessor = dyn_cast(this)) { // For a getter or setter, go through the variable or subscript decl. auto asd = accessor->getStorage(); if (accessor->isGetter()) return asd->getObjCGetterSelector(baseName); if (accessor->isSetter()) return asd->getObjCSetterSelector(baseName); } // If this is a zero-parameter initializer with a long selector // name, form that selector. auto ctor = dyn_cast(this); if (ctor && ctor->isObjCZeroParameterWithLongSelector()) { Identifier firstName = argNames[0]; llvm::SmallString<16> scratch; scratch += "init"; // If the first argument name doesn't start with a preposition, add "with". if (!isPreposition(camel_case::getFirstWord(firstName.str()))) { camel_case::appendSentenceCase(scratch, "With"); } camel_case::appendSentenceCase(scratch, firstName.str()); return ObjCSelector(ctx, 0, ctx.getIdentifier(scratch)); } // The number of selector pieces we'll have. std::optional asyncConvention = getForeignAsyncConvention(); std::optional errorConvention = getForeignErrorConvention(); unsigned numSelectorPieces = argNames.size() + (asyncConvention.has_value() ? 1 : 0) + (errorConvention.has_value() ? 1 : 0); // If we have no arguments, it's a nullary selector. if (numSelectorPieces == 0) { return ObjCSelector(ctx, 0, baseName); } // If it's a unary selector with no name for the first argument, we're done. if (numSelectorPieces == 1 && argNames.size() == 1 && argNames[0].empty()) { return ObjCSelector(ctx, 1, baseName); } /// Collect the selector pieces. SmallVector selectorPieces; selectorPieces.reserve(numSelectorPieces); bool didStringManipulation = false; unsigned argIndex = 0; for (unsigned piece = 0; piece != numSelectorPieces; ++piece) { if (piece > 0) { // If we have an async convention that inserts a completion handler // parameter here, add "completionHandler". if (asyncConvention && piece == asyncConvention->completionHandlerParamIndex()) { selectorPieces.push_back(ctx.getIdentifier("completionHandler")); continue; } // If we have an error convention that inserts an error parameter // here, add "error". if (errorConvention && piece == errorConvention->getErrorParameterIndex()) { selectorPieces.push_back(ctx.Id_error); continue; } // Selector pieces beyond the first are simple. selectorPieces.push_back(argNames[argIndex++]); continue; } // For the first selector piece, attach either the first parameter, // "withCompletionHandler", or "AndReturnError" to the base name, // if appropriate. auto firstPiece = baseName; llvm::SmallString<32> scratch; scratch += firstPiece.str(); if (asyncConvention && piece == asyncConvention->completionHandlerParamIndex()) { // The completion handler is first; append "WithCompletionHandler". camel_case::appendSentenceCase(scratch, "WithCompletionHandler"); firstPiece = ctx.getIdentifier(scratch); didStringManipulation = true; } else if (errorConvention && piece == errorConvention->getErrorParameterIndex()) { // The error is first; append "AndReturnError". camel_case::appendSentenceCase(scratch, "AndReturnError"); firstPiece = ctx.getIdentifier(scratch); didStringManipulation = true; } else if (!argNames[argIndex].empty()) { // If the first argument name doesn't start with a preposition, and the // method name doesn't end with a preposition, add "with". auto firstName = argNames[argIndex++]; if (!isPreposition(camel_case::getFirstWord(firstName.str())) && !isPreposition(camel_case::getLastWord(firstPiece.str()))) { camel_case::appendSentenceCase(scratch, "With"); } camel_case::appendSentenceCase(scratch, firstName.str()); firstPiece = ctx.getIdentifier(scratch); didStringManipulation = true; } else { ++argIndex; } selectorPieces.push_back(firstPiece); } assert(argIndex == argNames.size()); // Form the result. auto result = ObjCSelector(ctx, selectorPieces.size(), selectorPieces); // If we did any string manipulation, cache the result. We don't want to // do that again. if (didStringManipulation && objc && !preferredName) const_cast(objc)->setName(result, /*implicit=*/true); return result; } bool AbstractFunctionDecl::isObjCInstanceMethod() const { return isInstanceMember() || isa(this); } bool AbstractFunctionDecl::needsNewVTableEntry() const { auto &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, NeedsNewVTableEntryRequest{const_cast(this)}, false); } ParamDecl *AbstractFunctionDecl::getImplicitSelfDecl(bool createIfNeeded) { auto **selfDecl = getImplicitSelfDeclStorage(); // If this is not a method, return nullptr. if (selfDecl == nullptr) return nullptr; // If we've already created a 'self' parameter, just return it. if (*selfDecl != nullptr) return *selfDecl; // If we're not allowed to create one, return nullptr. if (!createIfNeeded) return nullptr; // Create and save our 'self' parameter. auto &ctx = getASTContext(); *selfDecl = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), getLoc(), ctx.Id_self, this); (*selfDecl)->setImplicit(); return *selfDecl; } void AbstractFunctionDecl::setParameters(ParameterList *BodyParams) { #ifndef NDEBUG const auto Name = getName(); if (!isa(this)) assert((!Name || !Name.isSimpleName()) && "Must have a compound name"); assert(!Name || (Name.getArgumentNames().size() == BodyParams->size())); #endif Params = BodyParams; BodyParams->setDeclContextOfParamDecls(this); } OpaqueTypeDecl::OpaqueTypeDecl(ValueDecl *NamingDecl, GenericParamList *GenericParams, DeclContext *DC, GenericSignature OpaqueInterfaceGenericSignature, ArrayRef OpaqueReturnTypeReprs) : GenericTypeDecl(DeclKind::OpaqueType, DC, Identifier(), SourceLoc(), {}, GenericParams), NamingDeclAndHasOpaqueReturnTypeRepr( NamingDecl, !OpaqueReturnTypeReprs.empty()), OpaqueInterfaceGenericSignature(OpaqueInterfaceGenericSignature) { // Always implicit. setImplicit(); /// We either have no opaque return type representations ('some P'), or we /// have one for each opaque generic parameter. assert(OpaqueReturnTypeReprs.empty() || OpaqueReturnTypeReprs.size() == OpaqueInterfaceGenericSignature.getInnermostGenericParams().size()); std::uninitialized_copy( OpaqueReturnTypeReprs.begin(), OpaqueReturnTypeReprs.end(), getTrailingObjects()); } OpaqueTypeDecl *OpaqueTypeDecl::get( ValueDecl *NamingDecl, GenericParamList *GenericParams, DeclContext *DC, GenericSignature OpaqueInterfaceGenericSignature, ArrayRef OpaqueReturnTypeReprs) { ASTContext &ctx = DC->getASTContext(); auto size = totalSizeToAlloc( OpaqueReturnTypeReprs.size()); auto mem = ctx.Allocate(size, alignof(OpaqueTypeDecl)); return new (mem) OpaqueTypeDecl( NamingDecl, GenericParams, DC, OpaqueInterfaceGenericSignature, OpaqueReturnTypeReprs); } bool OpaqueTypeDecl::isOpaqueReturnTypeOfFunction( const AbstractFunctionDecl *func) const { // Either the function is declared with its own opaque return type... if (getNamingDecl() == func) return true; // ...or the function is a getter for a property or subscript with an // opaque return type. if (auto accessor = dyn_cast(func)) { return accessor->isGetter() && getNamingDecl() == accessor->getStorage(); } return false; } bool OpaqueTypeDecl::hasExplicitGenericParams() const { return getExplicitGenericParam(0) != nullptr; } GenericTypeParamDecl *OpaqueTypeDecl::getExplicitGenericParam( unsigned ordinal) const { if (ordinal >= getOpaqueGenericParams().size()) return nullptr; auto genericParamType = getOpaqueGenericParams()[ordinal]; return genericParamType->getDecl(); } bool OpaqueTypeDecl::exportUnderlyingType() const { auto mod = getDeclContext()->getParentModule(); if (mod->getResilienceStrategy() != ResilienceStrategy::Resilient) return true; // If we perform package CMO, in-package clients must have access to the // underlying type. if (mod->serializePackageEnabled()) return true; ValueDecl *namingDecl = getNamingDecl(); if (auto *AFD = dyn_cast(namingDecl)) return AFD->getResilienceExpansion() == ResilienceExpansion::Minimal; if (auto *ASD = dyn_cast(namingDecl)) { for (auto *accessor : ASD->getAllAccessors()) if (accessor->getResilienceExpansion() == ResilienceExpansion::Minimal) return true; return false; } llvm_unreachable("The naming decl is expected to be either an AFD or ASD"); } std::optional OpaqueTypeDecl::getUniqueUnderlyingTypeSubstitutions() const { return evaluateOrDefault(getASTContext().evaluator, UniqueUnderlyingTypeSubstitutionsRequest{this}, {}); } std::optional OpaqueTypeDecl::getAnonymousOpaqueParamOrdinal(TypeRepr *repr) const { assert(NamingDeclAndHasOpaqueReturnTypeRepr.getInt() && "can't do opaque param lookup without underlying interface repr"); auto opaqueReprs = getOpaqueReturnTypeReprs(); auto found = std::find(opaqueReprs.begin(), opaqueReprs.end(), repr); if (found != opaqueReprs.end()) return found - opaqueReprs.begin(); return std::nullopt; } Identifier OpaqueTypeDecl::getOpaqueReturnTypeIdentifier() const { assert(getNamingDecl() && "not an opaque return type"); if (!OpaqueReturnTypeIdentifier.empty()) return OpaqueReturnTypeIdentifier; SmallString<64> mangleBuf; { llvm::raw_svector_ostream os(mangleBuf); Mangle::ASTMangler mangler; os << mangler.mangleOpaqueTypeDecl(this); } OpaqueReturnTypeIdentifier = getASTContext().getIdentifier(mangleBuf); return OpaqueReturnTypeIdentifier; } void OpaqueTypeDecl::setConditionallyAvailableSubstitutions( ArrayRef substitutions) { assert(!ConditionallyAvailableTypes && "resetting conditionally available substitutions?!"); ConditionallyAvailableTypes = getASTContext().AllocateCopy(substitutions); } OpaqueTypeDecl::ConditionallyAvailableSubstitutions * OpaqueTypeDecl::ConditionallyAvailableSubstitutions::get( ASTContext &ctx, ArrayRef availabilityContext, SubstitutionMap substitutions) { auto size = totalSizeToAlloc(availabilityContext.size()); auto mem = ctx.Allocate(size, alignof(ConditionallyAvailableSubstitutions)); return new (mem) ConditionallyAvailableSubstitutions(availabilityContext, substitutions); } bool AbstractFunctionDecl::hasInlinableBodyText() const { switch (getBodyKind()) { case BodyKind::Deserialized: return true; case BodyKind::Unparsed: case BodyKind::Parsed: case BodyKind::TypeChecked: if (auto body = getBody()) return !body->isImplicit(); return false; case BodyKind::None: case BodyKind::Synthesize: case BodyKind::SILSynthesize: return false; } llvm_unreachable("covered switch"); } StringRef AbstractFunctionDecl::getInlinableBodyText( SmallVectorImpl &scratch) const { assert(hasInlinableBodyText() && "can't get string representation of function with no text"); if (getBodyKind() == BodyKind::Deserialized) return BodyStringRepresentation; auto body = getBody(); return extractInlinableText(getASTContext(), body, scratch); } /// A uniqued list of derivative function configurations. struct AbstractFunctionDecl::DerivativeFunctionConfigurationList : public ASTAllocated, public llvm::SetVector {}; void AbstractFunctionDecl::prepareDerivativeFunctionConfigurations() { if (DerivativeFunctionConfigs) return; auto &ctx = getASTContext(); DerivativeFunctionConfigs = new (ctx) DerivativeFunctionConfigurationList(); // Register an `ASTContext` cleanup calling the list destructor. ctx.addCleanup([this]() { this->DerivativeFunctionConfigs->~DerivativeFunctionConfigurationList(); }); } ArrayRef AbstractFunctionDecl::getDerivativeFunctionConfigurations() { prepareDerivativeFunctionConfigurations(); // Resolve derivative function configurations from `@differentiable` // attributes by type-checking them. for (auto *diffAttr : getAttrs().getAttributes()) (void)diffAttr->getParameterIndices(); // For accessors: resolve derivative function configurations from storage // `@differentiable` attributes by type-checking them. if (auto *accessor = dyn_cast(this)) { auto *storage = accessor->getStorage(); for (auto *diffAttr : storage->getAttrs().getAttributes()) (void)diffAttr->getParameterIndices(); } // Load derivative configurations from imported modules. auto &ctx = getASTContext(); if (ctx.getCurrentGeneration() > DerivativeFunctionConfigGeneration) { unsigned previousGeneration = DerivativeFunctionConfigGeneration; DerivativeFunctionConfigGeneration = ctx.getCurrentGeneration(); ctx.loadDerivativeFunctionConfigurations(this, previousGeneration, *DerivativeFunctionConfigs); } return DerivativeFunctionConfigs->getArrayRef(); } void AbstractFunctionDecl::addDerivativeFunctionConfiguration( const AutoDiffConfig &config) { prepareDerivativeFunctionConfigurations(); DerivativeFunctionConfigs->insert(config); } std::optional> AbstractFunctionDecl::getLifetimeDependencies() const { if (!isa(this) && !isa(this)) { return std::nullopt; } return evaluateOrDefault( getASTContext().evaluator, LifetimeDependenceInfoRequest{const_cast(this)}, std::nullopt); } void FuncDecl::setResultInterfaceType(Type type) { getASTContext().evaluator.cacheOutput(ResultTypeRequest{this}, std::move(type)); } void FuncDecl::setDeserializedResultTypeLoc(TypeLoc ResultTyR) { FnRetType = ResultTyR; } FuncDecl *FuncDecl::createImpl(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, bool Async, SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, TypeLoc ThrownTy, GenericParamList *GenericParams, DeclContext *Parent, ClangNode ClangN) { bool HasImplicitSelfDecl = Parent->isTypeContext(); size_t Size = sizeof(FuncDecl) + (HasImplicitSelfDecl ? sizeof(ParamDecl *) : 0); void *DeclPtr = allocateMemoryForDecl(Context, Size, !ClangN.isNull()); auto D = ::new (DeclPtr) FuncDecl(DeclKind::Func, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, ThrownTy, HasImplicitSelfDecl, GenericParams, Parent); if (ClangN) D->setClangNode(ClangN); if (HasImplicitSelfDecl) *D->getImplicitSelfDeclStorage() = nullptr; return D; } FuncDecl *FuncDecl::createDeserialized(ASTContext &Context, StaticSpellingKind StaticSpelling, DeclName Name, bool Async, bool Throws, Type ThrownType, GenericParamList *GenericParams, Type FnRetType, DeclContext *Parent) { assert(FnRetType && "Deserialized result type must not be null"); auto *const FD = FuncDecl::createImpl(Context, SourceLoc(), StaticSpelling, SourceLoc(), Name, SourceLoc(), Async, SourceLoc(), Throws, SourceLoc(), TypeLoc::withoutLoc(ThrownType), GenericParams, Parent, ClangNode()); FD->setResultInterfaceType(FnRetType); return FD; } FuncDecl *FuncDecl::create(ASTContext &Context, SourceLoc StaticLoc, StaticSpellingKind StaticSpelling, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, bool Async, SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, TypeRepr *ThrownTyR, GenericParamList *GenericParams, ParameterList *BodyParams, TypeRepr *ResultTyR, DeclContext *Parent) { auto *const FD = FuncDecl::createImpl( Context, StaticLoc, StaticSpelling, FuncLoc, Name, NameLoc, Async, AsyncLoc, Throws, ThrowsLoc, ThrownTyR, GenericParams, Parent, ClangNode()); FD->setParameters(BodyParams); FD->FnRetType = TypeLoc(ResultTyR); if (llvm::isa_and_nonnull(ResultTyR)) FD->setSendingResult(); return FD; } FuncDecl *FuncDecl::createImplicit(ASTContext &Context, StaticSpellingKind StaticSpelling, DeclName Name, SourceLoc NameLoc, bool Async, bool Throws, Type ThrownType, GenericParamList *GenericParams, ParameterList *BodyParams, Type FnRetType, DeclContext *Parent) { assert(FnRetType); auto *const FD = FuncDecl::createImpl( Context, SourceLoc(), StaticSpelling, SourceLoc(), Name, NameLoc, Async, SourceLoc(), Throws, SourceLoc(), TypeLoc::withoutLoc(ThrownType), GenericParams, Parent, ClangNode()); FD->setImplicit(); FD->setParameters(BodyParams); FD->setResultInterfaceType(FnRetType); return FD; } FuncDecl *FuncDecl::createImported(ASTContext &Context, SourceLoc FuncLoc, DeclName Name, SourceLoc NameLoc, bool Async, bool Throws, Type ThrownType, ParameterList *BodyParams, Type FnRetType, GenericParamList *GenericParams, DeclContext *Parent, ClangNode ClangN) { assert(ClangN); auto *const FD = FuncDecl::createImpl( Context, SourceLoc(), StaticSpellingKind::None, FuncLoc, Name, NameLoc, Async, SourceLoc(), Throws, SourceLoc(), TypeLoc::withoutLoc(ThrownType), GenericParams, Parent, ClangN); FD->setParameters(BodyParams); FD->setResultInterfaceType(FnRetType); return FD; } OperatorDecl *FuncDecl::getOperatorDecl() const { // Fast-path: Most functions are not operators. if (!isOperator()) { return nullptr; } return evaluateOrDefault(getASTContext().evaluator, FunctionOperatorRequest{ const_cast(this) }, nullptr); } bool FuncDecl::isStatic() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, IsStaticRequest{const_cast(this)}, false); } AccessorDecl *AccessorDecl::createImpl( ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc, AccessorKind accessorKind, AbstractStorageDecl *storage, bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc, TypeLoc thrownType, DeclContext *parent, ClangNode clangNode) { bool hasImplicitSelfDecl = parent->isTypeContext(); size_t size = sizeof(AccessorDecl) + (hasImplicitSelfDecl ? sizeof(ParamDecl *) : 0); void *buffer = allocateMemoryForDecl(ctx, size, !clangNode.isNull()); auto D = ::new (buffer) AccessorDecl( declLoc, accessorKeywordLoc, accessorKind, storage, async, asyncLoc, throws, throwsLoc, thrownType, hasImplicitSelfDecl, parent); if (clangNode) D->setClangNode(clangNode); if (hasImplicitSelfDecl) *D->getImplicitSelfDeclStorage() = nullptr; return D; } AccessorDecl *AccessorDecl::createDeserialized(ASTContext &ctx, AccessorKind accessorKind, AbstractStorageDecl *storage, bool async, bool throws, Type thrownType, Type fnRetType, DeclContext *parent) { assert(fnRetType && "Deserialized result type must not be null"); auto *const D = AccessorDecl::createImpl( ctx, SourceLoc(), SourceLoc(), accessorKind, storage, async, SourceLoc(), throws, SourceLoc(), TypeLoc::withoutLoc(thrownType), parent, ClangNode()); D->setResultInterfaceType(fnRetType); return D; } AccessorDecl *AccessorDecl::create(ASTContext &ctx, SourceLoc declLoc, SourceLoc accessorKeywordLoc, AccessorKind accessorKind, AbstractStorageDecl *storage, bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc, TypeLoc thrownType, ParameterList *bodyParams, Type fnRetType, DeclContext *parent, ClangNode clangNode) { auto *D = AccessorDecl::createImpl( ctx, declLoc, accessorKeywordLoc, accessorKind, storage, async, asyncLoc, throws, throwsLoc, thrownType, parent, clangNode); D->setParameters(bodyParams); D->setResultInterfaceType(fnRetType); return D; } AccessorDecl *AccessorDecl::createImplicit(ASTContext &ctx, AccessorKind accessorKind, AbstractStorageDecl *storage, bool async, bool throws, TypeLoc thrownType, Type fnRetType, DeclContext *parent) { AccessorDecl *D = AccessorDecl::createImpl( ctx, /*declLoc=*/SourceLoc(), /*accessorKeywordLoc=*/SourceLoc(), accessorKind, storage, async, /*asyncLoc=*/SourceLoc(), /*throws=*/true, /*throwsLoc=*/SourceLoc(), thrownType, parent, /*clangNode=*/ClangNode()); D->setImplicit(); D->setResultInterfaceType(fnRetType); return D; } AccessorDecl *AccessorDecl::createParsed( ASTContext &ctx, AccessorKind accessorKind, AbstractStorageDecl *storage, SourceLoc declLoc, SourceLoc accessorKeywordLoc, ParameterList *paramList, SourceLoc asyncLoc, SourceLoc throwsLoc, TypeRepr *thrownType, DeclContext *dc) { auto *accessor = AccessorDecl::createImpl( ctx, declLoc, accessorKeywordLoc, accessorKind, storage, /*async*/ asyncLoc.isValid(), asyncLoc, /*throws*/ throwsLoc.isValid(), throwsLoc, thrownType, dc, /*clangNode*/ ClangNode()); // Set up the parameter list. This is the "newValue" name (for setters), // followed by the index list (for subscripts). For non-subscript getters, // this degenerates down to "()". // // We put the 'newValue' argument before the subscript index list as a // micro-optimization for Objective-C thunk generation. SmallVector newParams; SourceLoc paramsStart, paramsEnd; if (paramList) { assert(paramList->size() == 1 && "Should only have a single parameter in the list"); newParams.push_back(paramList->get(0)); paramsStart = paramList->getStartLoc(); paramsEnd = paramList->getEndLoc(); } else { // No parameter list, if we have an implicit parameter name, fill it in. auto implicitName = AccessorDecl::implicitParameterNameFor(accessorKind); if (!implicitName.empty()) { auto *implicitParam = new (ctx) ParamDecl(SourceLoc(), SourceLoc(), Identifier(), declLoc, ctx.getIdentifier(implicitName), /*declContext*/ accessor); implicitParam->setImplicit(); newParams.push_back(implicitParam); } } // If this is a subscript accessor, we need to splice in the subscript // parameters into the accessor's parameter list. if (auto *SD = dyn_cast(storage)) { auto *indices = SD->getIndices(); if (paramsStart.isInvalid()) { paramsStart = indices->getStartLoc(); paramsEnd = indices->getEndLoc(); } for (auto *subscriptParam : *indices) { // Clone the parameter. auto *param = new (ctx) ParamDecl( subscriptParam->getSpecifierLoc(), subscriptParam->getArgumentNameLoc(), subscriptParam->getArgumentName(), subscriptParam->getNameLoc(), subscriptParam->getName(), /*declContext*/ accessor); param->setAutoClosure(subscriptParam->isAutoClosure()); // The cloned parameter is implicit. param->setImplicit(); newParams.push_back(param); } } accessor->setParameters( ParameterList::create(ctx, paramsStart, newParams, paramsEnd)); return accessor; } StringRef AccessorDecl::implicitParameterNameFor(AccessorKind kind) { switch (kind) { case AccessorKind::Set: case AccessorKind::WillSet: case AccessorKind::Init: return "newValue"; case AccessorKind::DidSet: return "oldValue"; case AccessorKind::Get: case AccessorKind::DistributedGet: case AccessorKind::Read: case AccessorKind::Read2: case AccessorKind::Modify: case AccessorKind::Modify2: case AccessorKind::Address: case AccessorKind::MutableAddress: return StringRef(); } } bool AccessorDecl::isAssumedNonMutating() const { switch (getAccessorKind()) { case AccessorKind::Get: case AccessorKind::DistributedGet: case AccessorKind::Address: case AccessorKind::Read: case AccessorKind::Read2: return true; case AccessorKind::Set: case AccessorKind::WillSet: case AccessorKind::DidSet: case AccessorKind::MutableAddress: case AccessorKind::Modify: case AccessorKind::Modify2: case AccessorKind::Init: return false; } llvm_unreachable("bad accessor kind"); } bool AccessorDecl::isExplicitNonMutating() const { return !isMutating() && !isAssumedNonMutating() && isInstanceMember() && !getDeclContext()->getDeclaredInterfaceType()->hasReferenceSemantics(); } bool AccessorDecl::isSimpleDidSet() const { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, SimpleDidSetRequest{mutableThis}, false); } void AccessorDecl::printUserFacingName(raw_ostream &out) const { switch (getAccessorKind()) { case AccessorKind::Get: out << "getter:"; break; case AccessorKind::DistributedGet: out << "_distributed_getter:"; break; case AccessorKind::Set: out << "setter:"; break; default: out << getName(); return; } out << getStorage()->getName() << "("; if (this->isSetter()) { for (const auto *param : *getParameters()) { out << param->getName() << ":"; } } out << ")"; } ArrayRef AccessorDecl::getInitializedProperties() const { assert(isInitAccessor()); if (auto *SR = getAttrs().getAttribute()) return SR->getInitializesProperties(const_cast(this)); return {}; } ArrayRef AccessorDecl::getAccessedProperties() const { assert(isInitAccessor()); if (auto *SR = getAttrs().getAttribute()) return SR->getAccessesProperties(const_cast(this)); return {}; } StaticSpellingKind FuncDecl::getCorrectStaticSpelling() const { assert(getDeclContext()->isTypeContext()); if (!isStatic()) return StaticSpellingKind::None; if (getStaticSpelling() != StaticSpellingKind::None) return getStaticSpelling(); return getCorrectStaticSpellingForDecl(this); } Type FuncDecl::getResultInterfaceType() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); if (auto type = evaluateOrDefault(ctx.evaluator, ResultTypeRequest{mutableThis}, Type())) return type; return ErrorType::get(ctx); } bool FuncDecl::isUnaryOperator() const { if (!isOperator()) return false; auto *params = getParameters(); return params->size() == 1 && !params->get(0)->isVariadic(); } bool FuncDecl::isBinaryOperator() const { if (!isOperator()) return false; auto *params = getParameters(); return params->size() == 2 && !params->get(0)->isVariadic() && !params->get(1)->isVariadic(); } SelfAccessKind FuncDecl::getSelfAccessKind() const { auto &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, SelfAccessKindRequest{const_cast(this)}, SelfAccessKind::NonMutating); } LifetimeAnnotation FuncDecl::getLifetimeAnnotation() const { // Copyable parameters which are consumed have eager-move semantics. if (getSelfAccessKind() == SelfAccessKind::Consuming) { auto *selfDecl = getImplicitSelfDecl(); if (selfDecl && !selfDecl->getTypeInContext()->isNoncopyable()) { if (getAttrs().hasAttribute()) return LifetimeAnnotation::Lexical; return LifetimeAnnotation::EagerMove; } } return getLifetimeAnnotationFromAttributes(); } bool FuncDecl::isCallAsFunctionMethod() const { return getBaseIdentifier() == getASTContext().Id_callAsFunction && isInstanceMember(); } bool FuncDecl::isMainTypeMainMethod() const { return (getBaseIdentifier() == getASTContext().Id_main) && !isInstanceMember() && getResultInterfaceType()->isVoid() && getParameters()->size() == 0; } ConstructorDecl::ConstructorDecl(DeclName Name, SourceLoc ConstructorLoc, bool Failable, SourceLoc FailabilityLoc, bool Async, SourceLoc AsyncLoc, bool Throws, SourceLoc ThrowsLoc, TypeLoc ThrownType, ParameterList *BodyParams, GenericParamList *GenericParams, DeclContext *Parent, TypeRepr *ResultTyR) : AbstractFunctionDecl(DeclKind::Constructor, Parent, Name, ConstructorLoc, Async, AsyncLoc, Throws, ThrowsLoc, ThrownType, /*HasImplicitSelfDecl=*/true, GenericParams), FailabilityLoc(FailabilityLoc), SelfDecl(nullptr) { if (BodyParams) setParameters(BodyParams); InitRetType = TypeLoc(ResultTyR); Bits.ConstructorDecl.HasStubImplementation = 0; Bits.ConstructorDecl.Failable = Failable; assert(Name.getBaseName().isConstructor()); } ConstructorDecl *ConstructorDecl::createImported( ASTContext &ctx, ClangNode clangNode, DeclName name, SourceLoc constructorLoc, bool failable, SourceLoc failabilityLoc, bool async, SourceLoc asyncLoc, bool throws, SourceLoc throwsLoc, Type thrownType, ParameterList *bodyParams, GenericParamList *genericParams, DeclContext *parent) { void *declPtr = allocateMemoryForDecl( ctx, sizeof(ConstructorDecl), true); auto ctor = ::new (declPtr) ConstructorDecl(name, constructorLoc, failable, failabilityLoc, async, asyncLoc, throws, throwsLoc, TypeLoc::withoutLoc(thrownType), bodyParams, genericParams, parent, /*LifetimeDependenceTypeRepr*/ nullptr); ctor->setClangNode(clangNode); return ctor; } void ConstructorDecl::setDeserializedResultTypeLoc(TypeLoc ResultTyR) { InitRetType = ResultTyR; } bool ConstructorDecl::isObjCZeroParameterWithLongSelector() const { // The initializer must have a single, non-empty argument name. if (getName().getArgumentNames().size() != 1 || getName().getArgumentNames()[0].empty()) return false; auto *params = getParameters(); if (params->size() != 1) return false; return params->get(0)->getInterfaceType()->isVoid(); } DestructorDecl::DestructorDecl(SourceLoc DestructorLoc, DeclContext *Parent) : AbstractFunctionDecl(DeclKind::Destructor, Parent, DeclBaseName::createDestructor(), DestructorLoc, /*Async=*/false, /*AsyncLoc=*/SourceLoc(), /*Throws=*/false, /*ThrowsLoc=*/SourceLoc(), /*ThrownType=*/TypeLoc(), /*HasImplicitSelfDecl=*/true, /*GenericParams=*/nullptr), SelfDecl(nullptr) { setParameters(ParameterList::createEmpty(Parent->getASTContext())); } ObjCSelector DestructorDecl::getObjCSelector() const { // Deinitializers are always called "dealloc". auto &ctx = getASTContext(); return ObjCSelector(ctx, 0, ctx.Id_dealloc); } DestructorDecl *DestructorDecl::getSuperDeinit() const { auto declContext = getDeclContext()->getImplementedObjCContext(); if (auto classDecl = dyn_cast(declContext)) { if (auto superclass = classDecl->getSuperclassDecl()) { return superclass->getDestructor(); } } return nullptr; } SourceRange FuncDecl::getSourceRange() const { SourceLoc StartLoc = getStartLoc(); if (StartLoc.isInvalid()) return SourceRange(); if (getBodyKind() == BodyKind::Unparsed) return { StartLoc, BodyRange.End }; SourceLoc RBraceLoc = getOriginalBodySourceRange().End; if (RBraceLoc.isValid()) { return { StartLoc, RBraceLoc }; } if (isa(this)) return StartLoc; if (getBodyKind() == BodyKind::Synthesize) return SourceRange(); auto TrailingWhereClauseSourceRange = getGenericTrailingWhereClauseSourceRange(); if (TrailingWhereClauseSourceRange.isValid()) return { StartLoc, TrailingWhereClauseSourceRange.End }; const auto ResultTyEndLoc = getResultTypeSourceRange().End; if (ResultTyEndLoc.isValid()) return { StartLoc, ResultTyEndLoc }; if (hasThrows()) return { StartLoc, getThrowsLoc() }; if (hasAsync()) return { StartLoc, getAsyncLoc() }; auto LastParamListEndLoc = getParameters()->getSourceRange().End; if (LastParamListEndLoc.isValid()) return { StartLoc, LastParamListEndLoc }; return StartLoc; } EnumElementDecl::EnumElementDecl(SourceLoc IdentifierLoc, DeclName Name, ParameterList *Params, SourceLoc EqualsLoc, LiteralExpr *RawValueExpr, DeclContext *DC) : DeclContext(DeclContextKind::EnumElementDecl, DC), ValueDecl(DeclKind::EnumElement, DC, Name, IdentifierLoc), EqualsLoc(EqualsLoc), RawValueExpr(RawValueExpr) { setParameterList(Params); } SourceRange EnumElementDecl::getSourceRange() const { if (RawValueExpr && !RawValueExpr->isImplicit()) return {getStartLoc(), RawValueExpr->getEndLoc()}; if (auto *PL = getParameterList()) return {getStartLoc(), PL->getSourceRange().End}; return {getStartLoc(), getNameLoc()}; } ArrayRef EnumElementDecl::getCaseConstructorParams() const { if (!hasAssociatedValues()) return {}; auto interfaceType = getInterfaceType(); if (interfaceType->is()) return {}; auto funcTy = interfaceType->castTo(); return funcTy->getResult()->castTo()->getParams(); } Type EnumElementDecl::getPayloadInterfaceType() const { if (!hasAssociatedValues()) return Type(); auto interfaceType = getInterfaceType(); if (interfaceType->is()) return interfaceType; // The payload type of an enum is an imploded tuple of the internal arguments // of the case constructor. As such, compose a tuple type with the parameter // flags dropped. return AnyFunctionType::composeTuple(getASTContext(), getCaseConstructorParams(), ParameterFlagHandling::IgnoreNonEmpty); } void EnumElementDecl::setParameterList(ParameterList *params) { Params = params; if (params) params->setDeclContextOfParamDecls(this); } EnumCaseDecl *EnumElementDecl::getParentCase() const { for (EnumCaseDecl *EC : getParentEnum()->getAllCases()) { ArrayRef CaseElements = EC->getElements(); if (std::find(CaseElements.begin(), CaseElements.end(), this) != CaseElements.end()) { return EC; } } llvm_unreachable("enum element not in case of parent enum"); } LiteralExpr *EnumElementDecl::getRawValueExpr() const { // The return value of this request is irrelevant - it exists as // a cache-warmer. (void)evaluateOrDefault( getASTContext().evaluator, EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Interface}, {}); return RawValueExpr; } LiteralExpr *EnumElementDecl::getStructuralRawValueExpr() const { // The return value of this request is irrelevant - it exists as // a cache-warmer. (void)evaluateOrDefault( getASTContext().evaluator, EnumRawValuesRequest{getParentEnum(), TypeResolutionStage::Structural}, {}); return RawValueExpr; } void EnumElementDecl::setRawValueExpr(LiteralExpr *e) { assert((!RawValueExpr || e == RawValueExpr || e->getType()) && "Illegal mutation of raw value expr"); RawValueExpr = e; } SourceRange ConstructorDecl::getSourceRange() const { if (isImplicit()) return getConstructorLoc(); SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) End = getGenericTrailingWhereClauseSourceRange().End; if (End.isInvalid()) End = getThrowsLoc(); if (End.isInvalid()) End = getSignatureSourceRange().End; return { getConstructorLoc(), End }; } Type ConstructorDecl::getResultInterfaceType() const { Type resultTy; auto *dc = getDeclContext(); if (!dc->isTypeContext()) resultTy = ErrorType::get(getASTContext()); else resultTy = dc->getSelfInterfaceType(); // Adjust result type for failability. if (isFailable()) return OptionalType::get(resultTy); return resultTy; } Type ConstructorDecl::getInitializerInterfaceType() { if (InitializerInterfaceType) return InitializerInterfaceType; // Lazily calculate initializer type. auto allocatorTy = getInterfaceType(); if (!allocatorTy->is()) { InitializerInterfaceType = ErrorType::get(getASTContext()); return InitializerInterfaceType; } auto funcTy = allocatorTy->castTo()->getResult(); assert(funcTy->is()); // Constructors have an initializer type that takes an instance // instead of a metatype. auto initSelfParam = computeSelfParam(this, /*isInitializingCtor=*/true); // FIXME: Verify ExtInfo state is correct, not working by accident. AnyFunctionType::ExtInfo info; if (initSelfParam.isIsolated()) info = info.withIsolation(FunctionTypeIsolation::forParameter()); Type initFuncTy; if (auto sig = getGenericSignature()) { initFuncTy = GenericFunctionType::get(sig, {initSelfParam}, funcTy, info); } else { initFuncTy = FunctionType::get({initSelfParam}, funcTy, info); } InitializerInterfaceType = initFuncTy; return InitializerInterfaceType; } CtorInitializerKind ConstructorDecl::getInitKind() const { const auto *ED = dyn_cast_or_null(getDeclContext()->getAsDecl()); if (ED && !ED->hasBeenBound()) { // When the declaration context is an extension and this is called when the // extended nominal hasn't be bound yet, e.g. dumping pre-typechecked AST, // there is not enough information about extended nominal to use for // computing init kind on InitKindRequest as bindExtensions is done at // typechecking, so in that case just look to parsed attribute in init // declaration. return getAttrs().hasAttribute() ? CtorInitializerKind::Convenience : CtorInitializerKind::Designated; } return evaluateOrDefault(getASTContext().evaluator, InitKindRequest{const_cast(this)}, CtorInitializerKind::Designated); } BodyInitKindAndExpr ConstructorDecl::getDelegatingOrChainedInitKind() const { return evaluateOrDefault(getASTContext().evaluator, BodyInitKindRequest{const_cast(this)}, BodyInitKindAndExpr()); assert(hasBody() && "Constructor does not have a definition"); } void ConstructorDecl::clearCachedDelegatingOrChainedInitKind() { getASTContext().evaluator.clearCachedOutput( BodyInitKindRequest{const_cast(this)}); } SourceRange DestructorDecl::getSourceRange() const { SourceLoc End = getOriginalBodySourceRange().End; if (End.isInvalid()) { End = getDestructorLoc(); } return { getDestructorLoc(), End }; } StringRef swift::getAssociativitySpelling(Associativity value) { switch (value) { case Associativity::None: return "none"; case Associativity::Left: return "left"; case Associativity::Right: return "right"; } llvm_unreachable("Unhandled Associativity in switch."); } PrecedenceGroupDecl * PrecedenceGroupDecl::create(DeclContext *dc, SourceLoc precedenceGroupLoc, SourceLoc nameLoc, Identifier name, SourceLoc lbraceLoc, SourceLoc associativityKeywordLoc, SourceLoc associativityValueLoc, Associativity associativity, SourceLoc assignmentKeywordLoc, SourceLoc assignmentValueLoc, bool isAssignment, SourceLoc higherThanLoc, ArrayRef higherThan, SourceLoc lowerThanLoc, ArrayRef lowerThan, SourceLoc rbraceLoc) { void *memory = dc->getASTContext().Allocate(sizeof(PrecedenceGroupDecl) + (higherThan.size() + lowerThan.size()) * sizeof(Relation), alignof(PrecedenceGroupDecl)); return new (memory) PrecedenceGroupDecl(dc, precedenceGroupLoc, nameLoc, name, lbraceLoc, associativityKeywordLoc, associativityValueLoc, associativity, assignmentKeywordLoc, assignmentValueLoc, isAssignment, higherThanLoc, higherThan, lowerThanLoc, lowerThan, rbraceLoc); } PrecedenceGroupDecl::PrecedenceGroupDecl(DeclContext *dc, SourceLoc precedenceGroupLoc, SourceLoc nameLoc, Identifier name, SourceLoc lbraceLoc, SourceLoc associativityKeywordLoc, SourceLoc associativityValueLoc, Associativity associativity, SourceLoc assignmentKeywordLoc, SourceLoc assignmentValueLoc, bool isAssignment, SourceLoc higherThanLoc, ArrayRef higherThan, SourceLoc lowerThanLoc, ArrayRef lowerThan, SourceLoc rbraceLoc) : Decl(DeclKind::PrecedenceGroup, dc), PrecedenceGroupLoc(precedenceGroupLoc), NameLoc(nameLoc), LBraceLoc(lbraceLoc), RBraceLoc(rbraceLoc), AssociativityKeywordLoc(associativityKeywordLoc), AssociativityValueLoc(associativityValueLoc), AssignmentKeywordLoc(assignmentKeywordLoc), AssignmentValueLoc(assignmentValueLoc), HigherThanLoc(higherThanLoc), LowerThanLoc(lowerThanLoc), Name(name), NumHigherThan(higherThan.size()), NumLowerThan(lowerThan.size()) { Bits.PrecedenceGroupDecl.Associativity = unsigned(associativity); Bits.PrecedenceGroupDecl.IsAssignment = isAssignment; memcpy(getHigherThanBuffer(), higherThan.data(), higherThan.size() * sizeof(Relation)); memcpy(getLowerThanBuffer(), lowerThan.data(), lowerThan.size() * sizeof(Relation)); } PrecedenceGroupDecl *InfixOperatorDecl::getPrecedenceGroup() const { return evaluateOrDefault( getASTContext().evaluator, OperatorPrecedenceGroupRequest{const_cast(this)}, nullptr); } bool FuncDecl::isDeferBody() const { return getBaseIdentifier() == getASTContext().getIdentifier("$defer"); } bool FuncDecl::isPotentialIBActionTarget() const { return isInstanceMember() && getDeclContext()->getSelfClassDecl() && !isa(this); } void FuncDecl::setHasTopLevelLocalContextCaptures(bool hasCaptures) { assert(!hasCaptures || isa(getDeclContext())); Bits.FuncDecl.HasTopLevelLocalContextCaptures = hasCaptures; } Type TypeBase::getSwiftNewtypeUnderlyingType() { auto structDecl = getStructOrBoundGenericStruct(); if (!structDecl) return {}; // Make sure the clang node has swift_newtype attribute auto clangNode = structDecl->getClangDecl(); if (!clangNode || !clangNode->hasAttr()) return {}; // Underlying type is the type of rawValue for (auto member : structDecl->getMembers()) if (auto varDecl = dyn_cast(member)) if (varDecl->getName() == getASTContext().Id_rawValue) return varDecl->getInterfaceType(); return {}; } const VarDecl *ClassDecl::getUnownedExecutorProperty() const { auto &C = getASTContext(); if (!isAnyActor()) return nullptr; llvm::SmallVector results; this->lookupQualified(getSelfNominalTypeDecl(), DeclNameRef(C.Id_unownedExecutor), getLoc(), NL_ProtocolMembers, results); for (auto candidate: results) { if (isa(candidate->getDeclContext())) continue; if (VarDecl *var = dyn_cast(candidate)) return var; } return nullptr; } bool ClassDecl::isRootDefaultActor() const { return isRootDefaultActor(getModuleContext(), ResilienceExpansion::Maximal); } bool ClassDecl::isRootDefaultActor(ModuleDecl *M, ResilienceExpansion expansion) const { if (!isDefaultActor(M, expansion)) return false; auto superclass = getSuperclassDecl(); return (!superclass || superclass->isNSObject()); } bool ClassDecl::isNonDefaultExplicitDistributedActor() const { return isNonDefaultExplicitDistributedActor(getModuleContext(), ResilienceExpansion::Maximal); } bool ClassDecl::isNonDefaultExplicitDistributedActor(ModuleDecl *M, ResilienceExpansion expansion) const { return !isDefaultActor(M, expansion) && isExplicitDistributedActor(); } bool ClassDecl::isNativeNSObjectSubclass() const { // @objc actors implicitly inherit from NSObject. if (isActor()) { if (getAttrs().hasAttribute()) { return true; } ClassDecl *superclass = getSuperclassDecl(); return superclass && superclass->isNSObject(); } // For now, non-actor classes cannot use the native NSObject subclass. // Eventually we should roll this out to more classes that directly // inherit NSObject, but we have to do it with ABI compatibility. return false; } bool ClassDecl::isNSObject() const { if (!getName().is("NSObject")) return false; ASTContext &ctx = getASTContext(); return (getModuleContext()->getName() == ctx.Id_Foundation || getModuleContext()->getName() == ctx.Id_ObjectiveC || getModuleContext()->getName().is("SwiftFoundation")); } Type ClassDecl::getSuperclass() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault(ctx.evaluator, SuperclassTypeRequest{const_cast(this), TypeResolutionStage::Interface}, Type()); } ClassDecl *ClassDecl::getSuperclassDecl() const { ASTContext &ctx = getASTContext(); auto result = evaluateOrDefault(ctx.evaluator, SuperclassDeclRequest{const_cast(this)}, const_cast(this)); if (result == this) return nullptr; return result; } void ClassDecl::setSuperclass(Type superclass) { assert((!superclass || !superclass->hasArchetype()) && "superclass must be interface type"); LazySemanticInfo.SuperclassType.setPointerAndInt(superclass, true); LazySemanticInfo.SuperclassDecl.setPointerAndInt( superclass ? superclass->getClassOrBoundGenericClass() : nullptr, true); } bool VarDecl::isSelfParamCaptureIsolated() const { assert(isSelfParamCapture()); // Find the "self" parameter that we captured and determine whether // it is potentially isolated. for (auto dc = getDeclContext(); dc; dc = dc->getParent()) { if (auto func = dyn_cast(dc)) { if (auto selfDecl = func->getImplicitSelfDecl()) { return selfDecl->isIsolated(); } if (auto capture = func->getCaptureInfo().getIsolatedParamCapture()) return capture->isSelfParameter() || capture->isSelfParamCapture(); } if (auto closure = dyn_cast(dc)) { switch (auto isolation = closure->getActorIsolation()) { case ActorIsolation::Unspecified: case ActorIsolation::Nonisolated: case ActorIsolation::NonisolatedUnsafe: case ActorIsolation::GlobalActor: case ActorIsolation::Erased: return false; case ActorIsolation::ActorInstance: auto isolatedVar = isolation.getActorInstance(); return isolatedVar->isSelfParameter() || isolatedVar-isSelfParamCapture(); } } if (dc->isModuleScopeContext() || dc->isTypeContext()) break; } return false; } ActorIsolation swift::getActorIsolation(ValueDecl *value) { return getInferredActorIsolation(value).isolation; } InferredActorIsolation swift::getInferredActorIsolation(ValueDecl *value) { auto &ctx = value->getASTContext(); return evaluateOrDefault( ctx.evaluator, ActorIsolationRequest{value}, InferredActorIsolation::forUnspecified()); } ActorIsolation swift::getActorIsolationOfContext( DeclContext *dc, llvm::function_ref getClosureActorIsolation) { auto &ctx = dc->getASTContext(); auto dcToUse = dc; // Defer bodies share actor isolation of their enclosing context. if (auto FD = dyn_cast(dcToUse)) { if (FD->isDeferBody()) { dcToUse = FD->getDeclContext(); } } if (auto *vd = dyn_cast_or_null(dcToUse->getAsDecl())) return getActorIsolation(vd); // In the context of the initializing or default-value expression of a // stored property: // - For a static stored property, the isolation matches the VarDecl. // Static properties are initialized upon first use, so the isolation // of the initializer must match the isolation required to access the // property. // - For a field of a nominal type, the expression can require the same // actor isolation as the field itself. That default expression may only // be used from inits that meet the required isolation. if (auto *var = dcToUse->getNonLocalVarDecl()) { // If IsolatedDefaultValues are enabled, treat this context as having // unspecified isolation. We'll compute the required isolation for // the initializer and validate that it matches the isolation of the // var itself in the DefaultInitializerIsolation request. if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues)) return ActorIsolation::forUnspecified(); return getActorIsolation(var); } if (auto *closure = dyn_cast(dcToUse)) { return getClosureActorIsolation(closure); } if (auto *tld = dyn_cast(dcToUse)) { if (dcToUse->isAsyncContext() || dcToUse->getASTContext().LangOpts.StrictConcurrencyLevel >= StrictConcurrency::Complete) { if (Type mainActor = dcToUse->getASTContext().getMainActorType()) return ActorIsolation::forGlobalActor(mainActor) .withPreconcurrency( !dcToUse->getASTContext().isSwiftVersionAtLeast(6)); } } return ActorIsolation::forUnspecified(); } bool swift::isSameActorIsolated(ValueDecl *value, DeclContext *dc) { auto valueIsolation = getActorIsolation(value); auto dcIsolation = getActorIsolationOfContext(dc); return valueIsolation.isActorIsolated() && dcIsolation.isActorIsolated() && valueIsolation.getActor() == dcIsolation.getActor(); } ClangNode Decl::getClangNodeImpl() const { assert(Bits.Decl.FromClang); void * const *ptr = nullptr; switch (getKind()) { #define DECL(Id, Parent) \ case DeclKind::Id: \ ptr = reinterpret_cast(static_cast(this)); \ break; #include "swift/AST/DeclNodes.def" } return ClangNode::getFromOpaqueValue(*(ptr - 1)); } void Decl::setClangNode(ClangNode Node) { Bits.Decl.FromClang = true; // The extra/preface memory is allocated by the importer. void **ptr = nullptr; switch (getKind()) { #define DECL(Id, Parent) \ case DeclKind::Id: \ ptr = reinterpret_cast(static_cast(this)); \ break; #include "swift/AST/DeclNodes.def" } *(ptr - 1) = Node.getOpaqueValue(); } // See swift/Basic/Statistic.h for declaration: this enables tracing Decls, is // defined here to avoid too much layering violation / circular linkage // dependency. struct DeclTraceFormatter : public UnifiedStatsReporter::TraceFormatter { void traceName(const void *Entity, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); if (auto const *VD = dyn_cast(D)) { VD->getName().print(OS, false); } else { OS << "<" << Decl::getDescriptiveKindName(D->getDescriptiveKind()) << ">"; } } void traceLoc(const void *Entity, SourceManager *SM, clang::SourceManager *CSM, raw_ostream &OS) const override { if (!Entity) return; const Decl *D = static_cast(Entity); D->getSourceRange().print(OS, *SM, false); } }; static DeclTraceFormatter TF; template<> const UnifiedStatsReporter::TraceFormatter* FrontendStatsTracer::getTraceFormatter() { return &TF; } TypeOrExtensionDecl::TypeOrExtensionDecl(NominalTypeDecl *D) : Decl(D) {} TypeOrExtensionDecl::TypeOrExtensionDecl(ExtensionDecl *D) : Decl(D) {} Decl *TypeOrExtensionDecl::getAsDecl() const { if (auto NTD = Decl.dyn_cast()) return NTD; return Decl.get(); } DeclContext *TypeOrExtensionDecl::getAsDeclContext() const { return getAsDecl()->getInnermostDeclContext(); } IterableDeclContext *TypeOrExtensionDecl::getAsIterableDeclContext() const { if (auto nominal = Decl.dyn_cast()) return nominal; return Decl.get(); } NominalTypeDecl *TypeOrExtensionDecl::getBaseNominal() const { return getAsDeclContext()->getSelfNominalTypeDecl(); } bool TypeOrExtensionDecl::isNull() const { return Decl.isNull(); } void swift::simple_display(llvm::raw_ostream &out, const Decl *decl) { if (!decl) { out << "(null)"; return; } if (auto value = dyn_cast(decl)) { return simple_display(out, value); } else if (auto ext = dyn_cast(decl)) { out << "extension of "; if (auto typeRepr = ext->getExtendedTypeRepr()) typeRepr->print(out); else ext->getSelfNominalTypeDecl()->dumpRef(out); } else if (auto med = dyn_cast(decl)) { out << '#' << med->getMacroName() << " in "; printContext(out, med->getDeclContext()); } else { out << "(unknown decl)"; } if (decl->getLoc().isValid()) { out << '@'; decl->getLoc().print(out, decl->getASTContext().SourceMgr); } } void swift::simple_display(llvm::raw_ostream &out, OptionSet opts) { out << "{ "; using LookupFlags = NominalTypeDecl::LookupDirectFlags; if (opts.contains(LookupFlags::IncludeAttrImplements)) out << "IncludeAttrImplements"; out << " }"; } void swift::simple_display(llvm::raw_ostream &out, TypeOrExtensionDecl container) { simple_display(out, container.getAsDecl()); } void swift::simple_display(llvm::raw_ostream &out, const ValueDecl *decl) { if (decl) decl->dumpRef(out); else out << "(null)"; } void swift::simple_display(llvm::raw_ostream &out, const GenericParamList *GPL) { if (GPL) GPL->print(out); else out << "(null)"; } StringRef swift::getAccessorLabel(AccessorKind kind) { switch (kind) { #define SINGLETON_ACCESSOR(ID, KEYWORD) \ case AccessorKind::ID: return #KEYWORD; #define ACCESSOR(ID) #include "swift/AST/AccessorKinds.def" } llvm_unreachable("bad accessor kind"); } void swift::simple_display(llvm::raw_ostream &out, AccessorKind kind) { out << getAccessorLabel(kind); } SourceLoc swift::extractNearestSourceLoc(const Decl *decl) { auto loc = decl->getLoc(/*SerializedOK=*/false); if (loc.isValid()) return loc; return extractNearestSourceLoc(decl->getDeclContext()); } SourceLoc swift::extractNearestSourceLoc(TypeOrExtensionDecl container) { return extractNearestSourceLoc(container.Decl); } std::optional ParseAbstractFunctionBodyRequest::getCachedResult() const { using BodyKind = AbstractFunctionDecl::BodyKind; auto afd = std::get<0>(getStorage()); switch (afd->getBodyKind()) { case BodyKind::Deserialized: case BodyKind::SILSynthesize: case BodyKind::None: return BodyAndFingerprint{}; case BodyKind::TypeChecked: case BodyKind::Parsed: return afd->BodyAndFP; case BodyKind::Synthesize: case BodyKind::Unparsed: return std::nullopt; } llvm_unreachable("Unhandled BodyKing in switch"); } void ParseAbstractFunctionBodyRequest::cacheResult( BodyAndFingerprint value) const { using BodyKind = AbstractFunctionDecl::BodyKind; auto afd = std::get<0>(getStorage()); switch (afd->getBodyKind()) { case BodyKind::Deserialized: case BodyKind::SILSynthesize: // The body is always empty, so don't cache anything. assert(!value.getFingerprint().has_value() && value.getBody() == nullptr); return; case BodyKind::Parsed: case BodyKind::TypeChecked: case BodyKind::None: afd->BodyAndFP = value; return; case BodyKind::Synthesize: case BodyKind::Unparsed: llvm_unreachable("evaluate() did not set the body kind"); return; } } std::optional IsFunctionBodySkippedRequest::getCachedResult() const { using BodySkippedStatus = AbstractFunctionDecl::BodySkippedStatus; auto afd = std::get<0>(getStorage()); switch (afd->getBodySkippedStatus()) { case BodySkippedStatus::Unknown: return std::nullopt; case BodySkippedStatus::Skipped: return true; case BodySkippedStatus::NotSkipped: return false; } llvm_unreachable("bad BodySkippedStatus"); } void IsFunctionBodySkippedRequest::cacheResult(bool isSkipped) const { using BodySkippedStatus = AbstractFunctionDecl::BodySkippedStatus; auto afd = std::get<0>(getStorage()); const_cast(afd)->setBodySkippedStatus( isSkipped ? BodySkippedStatus::Skipped : BodySkippedStatus::NotSkipped); } void swift::simple_display(llvm::raw_ostream &out, BodyAndFingerprint value) { out << "("; simple_display(out, value.getBody()); out << ", "; simple_display(out, value.getFingerprint()); out << ")"; } void swift::simple_display(llvm::raw_ostream &out, AnyFunctionRef fn) { if (auto func = fn.getAbstractFunctionDecl()) simple_display(out, func); else out << "closure"; } BuiltinTupleDecl::BuiltinTupleDecl(Identifier Name, DeclContext *Parent) : NominalTypeDecl(DeclKind::BuiltinTuple, Parent, Name, SourceLoc(), ArrayRef(), nullptr) {} std::vector swift::getAllMacroRoles() { return { #define MACRO_ROLE(Name, Description) MacroRole::Name, #include "swift/Basic/MacroRoles.def" }; } StringRef swift::getMacroRoleString(MacroRole role) { switch (role) { #define MACRO_ROLE(Name, Description) \ case MacroRole::Name: \ return Description; #include "swift/Basic/MacroRoles.def" } } std::vector swift::getAllMacroIntroducedDeclNameKinds() { return { MacroIntroducedDeclNameKind::Named, MacroIntroducedDeclNameKind::Overloaded, MacroIntroducedDeclNameKind::Prefixed, MacroIntroducedDeclNameKind::Suffixed, MacroIntroducedDeclNameKind::Arbitrary, }; } bool swift::macroIntroducedNameRequiresArgument( MacroIntroducedDeclNameKind kind ) { switch (kind) { case MacroIntroducedDeclNameKind::Named: case MacroIntroducedDeclNameKind::Prefixed: case MacroIntroducedDeclNameKind::Suffixed: return true; case MacroIntroducedDeclNameKind::Overloaded: case MacroIntroducedDeclNameKind::Arbitrary: return false; } } StringRef swift::getMacroIntroducedDeclNameString( MacroIntroducedDeclNameKind kind) { switch (kind) { case MacroIntroducedDeclNameKind::Named: return "named"; case MacroIntroducedDeclNameKind::Overloaded: return "overloaded"; case MacroIntroducedDeclNameKind::Prefixed: return "prefixed"; case MacroIntroducedDeclNameKind::Suffixed: return "suffixed"; case MacroIntroducedDeclNameKind::Arbitrary: return "arbitrary"; } } static MacroRoles freestandingMacroRoles = (MacroRoles() #define FREESTANDING_MACRO_ROLE(Name, Description) | MacroRole::Name #define ATTACHED_MACRO_ROLE(Name, Description, MangledChar) #include "swift/Basic/MacroRoles.def" ); static MacroRoles attachedMacroRoles = (MacroRoles() #define ATTACHED_MACRO_ROLE(Name, Description, MangledChar) | MacroRole::Name #define FREESTANDING_MACRO_ROLE(Name, Description) #include "swift/Basic/MacroRoles.def" ); bool swift::isFreestandingMacro(MacroRoles contexts) { return bool(contexts & freestandingMacroRoles); } MacroRoles swift::getFreestandingMacroRoles() { return freestandingMacroRoles; } bool swift::isAttachedMacro(MacroRoles contexts) { return bool(contexts & attachedMacroRoles); } MacroRoles swift::getAttachedMacroRoles() { return attachedMacroRoles; } bool swift::isMacroSupported(MacroRole role, ASTContext &ctx) { switch (role) { #define EXPERIMENTAL_ATTACHED_MACRO_ROLE(Name, Description, MangledChar, FeatureName) \ case MacroRole::Name: \ return ctx.LangOpts.hasFeature(Feature::FeatureName); #define EXPERIMENTAL_FREESTANDING_MACRO_ROLE(Name, Description, FeatureName) \ case MacroRole::Name: return ctx.LangOpts.hasFeature(Feature::FeatureName); #define MACRO_ROLE(Name, Description) #include "swift/Basic/MacroRoles.def" #define EXPERIMENTAL_ATTACHED_MACRO_ROLE(Name, Description, MangledChar, FeatureName) #define EXPERIMENTAL_FREESTANDING_MACRO_ROLE(Name, Description, FeatureName) #define MACRO_ROLE(Name, Description) case MacroRole::Name: #include "swift/Basic/MacroRoles.def" return true; } } void MissingDecl::forEachMacroExpandedDecl(MacroExpandedDeclCallback callback) { auto macroRef = unexpandedMacro.macroRef; auto *baseDecl = unexpandedMacro.baseDecl; // If the macro itself is a macro expansion expression, it should come with // a top-level code declaration that we can use for resolution. For such // cases, resolve the macro to determine whether it is a declaration or // code-item macro, meaning that it can produce declarations. In such cases, // expand the macro and use its substituted declaration (a MacroExpansionDecl) // instead. if (auto freestanding = macroRef.dyn_cast()) { if (auto expr = dyn_cast(freestanding)) { bool replacedWithDecl = false; if (auto tlcd = dyn_cast_or_null(baseDecl)) { ASTContext &ctx = tlcd->getASTContext(); if (auto macro = evaluateOrDefault( ctx.evaluator, ResolveMacroRequest{macroRef, tlcd->getDeclContext()}, nullptr)) { auto macroDecl = cast(macro.getDecl()); auto roles = macroDecl->getMacroRoles(); if (roles.contains(MacroRole::Declaration) || roles.contains(MacroRole::CodeItem)) { (void)evaluateOrDefault(ctx.evaluator, ExpandMacroExpansionExprRequest{expr}, std::nullopt); if (auto substituted = expr->getSubstituteDecl()) { macroRef = substituted; baseDecl = substituted; replacedWithDecl = true; } } } } // If we didn't end up replacing the macro expansion expression with // a declaration, we're done. if (!replacedWithDecl) return; } } if (!macroRef || !baseDecl) return; auto *module = getModuleContext(); baseDecl->visitAuxiliaryDecls([&](Decl *auxiliaryDecl) { SourceFile *sf = auxiliaryDecl->getLoc() ? module->getSourceFileContainingLocation(auxiliaryDecl->getLoc()) : auxiliaryDecl->getInnermostDeclContext()->getParentSourceFile(); // We only visit auxiliary decls that are macro expansions associated with // this macro reference. if (auto *med = macroRef.dyn_cast()) { auto medAsDecl = dyn_cast(med); auto medAsExpr = dyn_cast(med); if ((!medAsDecl || medAsDecl != sf->getMacroExpansion().dyn_cast()) && (!medAsExpr || medAsExpr != sf->getMacroExpansion().dyn_cast())) return; } else if (auto *attr = macroRef.dyn_cast()) { if (attr != sf->getAttachedMacroAttribute()) return; } else { return; } if (auto *vd = dyn_cast(auxiliaryDecl)) callback(vd); }); } MacroDecl::MacroDecl( SourceLoc macroLoc, DeclName name, SourceLoc nameLoc, GenericParamList *genericParams, ParameterList *parameterList, SourceLoc arrowLoc, TypeRepr *resultType, Expr *definition, DeclContext *parent ) : GenericContext(DeclContextKind::MacroDecl, parent, genericParams), ValueDecl(DeclKind::Macro, parent, name, nameLoc), macroLoc(macroLoc), parameterList(parameterList), arrowLoc(arrowLoc), resultType(resultType), definition(definition) { if (parameterList) parameterList->setDeclContextOfParamDecls(this); } Type MacroDecl::getResultInterfaceType() const { auto &ctx = getASTContext(); auto mutableThis = const_cast(this); if (auto type = evaluateOrDefault(ctx.evaluator, ResultTypeRequest{mutableThis}, Type())) return type; return ErrorType::get(ctx); } SourceRange MacroDecl::getSourceRange() const { SourceLoc endLoc = getNameLoc(); if (parameterList) endLoc = parameterList->getEndLoc(); if (resultType.getSourceRange().isValid()) endLoc = resultType.getSourceRange().End; if (definition) endLoc = definition->getEndLoc(); if (auto trailing = getTrailingWhereClause()) endLoc = trailing->getSourceRange().End; return SourceRange(macroLoc, endLoc); } MacroRoles MacroDecl::getMacroRoles() const { MacroRoles contexts = std::nullopt; for (auto attr : getAttrs().getAttributes()) contexts |= attr->getMacroRole(); return contexts; } const MacroRoleAttr *MacroDecl::getMacroRoleAttr(MacroRole role) const { for (auto attr : getAttrs().getAttributes()) if (attr->getMacroRole() == role) return attr; return nullptr; } DeclName MacroDecl::getUniqueNamePlaceholder(ASTContext &ctx) { return ctx.getIdentifier("$"); } bool MacroDecl::isUniqueNamePlaceholder(DeclName name) { return name.getBaseName().userFacingName() == "$"; } bool MacroDecl::isUniqueMacroName(StringRef name) { // Unique macro names are mangled names, which always start with "$s". if (!name.starts_with("$s")) return false; // Unique macro names end with fMu_. Match that. // Strip off the trailing _. if (name.back() != '_') return false; name = name.drop_back(); // Strip off trailing digits. This is the discriminator. while (isdigit(name.back())) name = name.drop_back(); // Check for fMu. return name.ends_with("fMu"); } bool MacroDecl::isUniqueMacroName(DeclBaseName name) { return isUniqueMacroName(name.userFacingName()); } void MacroDecl::getIntroducedNames(MacroRole role, ValueDecl *attachedTo, SmallVectorImpl &names) const { ASTContext &ctx = getASTContext(); auto *attr = getMacroRoleAttr(role); if (!attr) return; for (auto expandedName : attr->getNames()) { switch (expandedName.getKind()) { case MacroIntroducedDeclNameKind::Named: { names.push_back(DeclName(expandedName.getName())); break; } case MacroIntroducedDeclNameKind::Overloaded: { if (!attachedTo) break; names.push_back(attachedTo->getBaseName()); break; } case MacroIntroducedDeclNameKind::Prefixed: { if (!attachedTo) break; auto baseName = attachedTo->getBaseName(); std::string prefixedName; { llvm::raw_string_ostream out(prefixedName); out << expandedName.getName(); out << baseName.getIdentifier(); } Identifier nameId = ctx.getIdentifier(prefixedName); names.push_back(DeclName(nameId)); break; } case MacroIntroducedDeclNameKind::Suffixed: { if (!attachedTo) break; auto baseName = attachedTo->getBaseName(); std::string suffixedName; { llvm::raw_string_ostream out(suffixedName); out << baseName.getIdentifier(); out << expandedName.getName(); } Identifier nameId = ctx.getIdentifier(suffixedName); names.push_back(DeclName(nameId)); break; } case MacroIntroducedDeclNameKind::Arbitrary: names.push_back(MacroDecl::getArbitraryName()); break; } } // Add the unique name, if the macro can introduce declarations anywhere. switch (role) { case MacroRole::Expression: case MacroRole::Declaration: case MacroRole::Member: case MacroRole::Peer: case MacroRole::CodeItem: case MacroRole::Extension: names.push_back(MacroDecl::getUniqueNamePlaceholder(getASTContext())); break; case MacroRole::Accessor: case MacroRole::Conformance: case MacroRole::MemberAttribute: case MacroRole::Preamble: case MacroRole::Body: break; } } void MacroDecl::getIntroducedConformances( NominalTypeDecl *attachedTo, MacroRole role, SmallVectorImpl &conformances) const { auto *attr = getMacroRoleAttr(role); if (!attr) return; auto &ctx = getASTContext(); auto constraintTypes = evaluateOrDefault( ctx.evaluator, ResolveMacroConformances{attr, this}, {}); for (auto constraint : constraintTypes) { assert(constraint->isConstraintType()); std::function addConstraint = [&](Type constraint) -> void { if (auto *proto = constraint->getAs()) { conformances.push_back(proto->getProtocol()); return; } else if (auto *proto = constraint->getAs()) { conformances.push_back(proto->getDecl()); return; } auto *composition = constraint->castTo(); for (auto constraint : composition->getMembers()) { addConstraint(constraint); } }; addConstraint(constraint); } } MacroDefinition MacroDecl::getDefinition() const { return evaluateOrDefault( getASTContext().evaluator, MacroDefinitionRequest{const_cast(this)}, MacroDefinition::forUndefined()); } void MacroDecl::setDefinition(MacroDefinition definition) { getASTContext().evaluator.cacheOutput(MacroDefinitionRequest{this}, std::move(definition)); } std::optional MacroDecl::getBuiltinKind() const { auto def = getDefinition(); if (def.kind != MacroDefinition::Kind::Builtin) return std::nullopt; return def.getBuiltinKind(); } MacroDefinition MacroDefinition::forExpanded( ASTContext &ctx, StringRef expansionText, ArrayRef replacements, ArrayRef genericReplacements ) { return ExpandedMacroDefinition{ctx.AllocateCopy(expansionText), ctx.AllocateCopy(replacements), ctx.AllocateCopy(genericReplacements)}; } MacroExpansionDecl::MacroExpansionDecl(DeclContext *dc, MacroExpansionInfo *info) : Decl(DeclKind::MacroExpansion, dc), FreestandingMacroExpansion(FreestandingMacroKind::Decl, info) { } MacroExpansionDecl * MacroExpansionDecl::create( DeclContext *dc, SourceLoc poundLoc, DeclNameRef macro, DeclNameLoc macroLoc, SourceLoc leftAngleLoc, ArrayRef genericArgs, SourceLoc rightAngleLoc, ArgumentList *args ) { ASTContext &ctx = dc->getASTContext(); MacroExpansionInfo *info = new (ctx) MacroExpansionInfo{poundLoc, /*moduleName*/ DeclNameRef(), /*moduleNameLoc*/ DeclNameLoc(), macro, macroLoc, leftAngleLoc, rightAngleLoc, genericArgs, args ? args : ArgumentList::createImplicit(ctx, {})}; return new (ctx) MacroExpansionDecl(dc, info); } void MacroExpansionDecl::forEachExpandedNode( llvm::function_ref callback ) const { auto mutableThis = const_cast(this); auto bufferID = evaluateOrDefault( getASTContext().evaluator, ExpandMacroExpansionDeclRequest{mutableThis}, {}); auto &sourceMgr = getASTContext().SourceMgr; auto *moduleDecl = getModuleContext(); if (!bufferID) return; auto startLoc = sourceMgr.getLocForBufferStart(*bufferID); auto *sourceFile = moduleDecl->getSourceFileContainingLocation(startLoc); auto *macro = dyn_cast(getMacroRef().getDecl()); auto roles = macro->getMacroRoles(); for (auto node : sourceFile->getTopLevelItems()) { // The assumption here is that macros can only have a single // freestanding macro role. Expression macros can only produce // expressions, declaration macros can only produce declarations, // and code item macros can produce expressions, declarations, and // statements. if (roles.contains(MacroRole::Expression) && !node.is()) continue; if (roles.contains(MacroRole::Declaration) && !node.is()) continue; callback(node); } } /// Adjust the declaration context to find a point in the context hierarchy /// that the macro can be anchored on. DeclContext * MacroDiscriminatorContext::getInnermostMacroContext(DeclContext *dc) { switch (dc->getContextKind()) { case DeclContextKind::SubscriptDecl: // For a subscript, return its parent context. return getInnermostMacroContext(dc->getParent()); case DeclContextKind::EnumElementDecl: case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::SerializedAbstractClosure: case DeclContextKind::SerializedTopLevelCodeDecl: case DeclContextKind::Package: case DeclContextKind::Module: case DeclContextKind::FileUnit: case DeclContextKind::GenericTypeDecl: case DeclContextKind::ExtensionDecl: case DeclContextKind::MacroDecl: // These contexts are always fine return dc; case DeclContextKind::TopLevelCodeDecl: // For top-level code, use the enclosing source file as the context. return getInnermostMacroContext(dc->getParent()); case DeclContextKind::AbstractClosureExpr: { // For closures, we can mangle the closure if we're in a context we can // mangle. Check that context. auto adjustedParentDC = getInnermostMacroContext(dc->getParent()); if (adjustedParentDC == dc->getParent()) return dc; return adjustedParentDC; } case DeclContextKind::Initializer: // Initializers can be part of inferring types for variables, so we need // their context. return getInnermostMacroContext(dc->getParent()); } } /// Retrieve the parent discriminator context for the given macro. MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf( SourceLoc loc, DeclContext *origDC) { origDC = getInnermostMacroContext(origDC); if (loc.isInvalid()) return origDC; ASTContext &ctx = origDC->getASTContext(); SourceManager &sourceMgr = ctx.SourceMgr; auto bufferID = sourceMgr.findBufferContainingLoc(loc); auto generatedSourceInfo = sourceMgr.getGeneratedSourceInfo(bufferID); if (!generatedSourceInfo) return origDC; switch (generatedSourceInfo->kind) { // Attached macros #define FREESTANDING_MACRO_ROLE(Name, Description) \ case GeneratedSourceInfo::Name##MacroExpansion: #define ATTACHED_MACRO_ROLE(Name, Description, MangledChar) #include "swift/Basic/MacroRoles.def" { auto node = ASTNode::getFromOpaqueValue(generatedSourceInfo->astNode); if (auto expansion = cast_or_null( node.dyn_cast())) { if (!origDC->isChildContextOf(expansion->getDeclContext())) return MacroDiscriminatorContext(expansion); } else { auto expansionDecl = cast(node.get()); if (!origDC->isChildContextOf(expansionDecl->getDeclContext())) return MacroDiscriminatorContext(expansionDecl); } return origDC; } // Attached macros #define FREESTANDING_MACRO_ROLE(Name, Description) #define ATTACHED_MACRO_ROLE(Name, Description, MangledChar) \ case GeneratedSourceInfo::Name##MacroExpansion: #include "swift/Basic/MacroRoles.def" case GeneratedSourceInfo::PrettyPrinted: case GeneratedSourceInfo::ReplacedFunctionBody: case GeneratedSourceInfo::DefaultArgument: return origDC; } } MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf(FreestandingMacroExpansion *expansion) { return getParentOf( expansion->getPoundLoc(), expansion->getDeclContext()); } std::optional CatchNode::getThrownErrorTypeInContext(ASTContext &ctx) const { if (auto func = dyn_cast()) { if (auto thrownError = func->getEffectiveThrownErrorType()) return func->mapTypeIntoContext(*thrownError); return std::nullopt; } if (auto closure = dyn_cast()) { if (closure->getType()) return closure->getEffectiveThrownType(); if (Type thrownType = closure->getExplicitThrownType()) { if (thrownType->isNever()) return std::nullopt; return thrownType; } return std::nullopt; } if (auto doCatch = dyn_cast()) { if (auto thrownError = doCatch->getCaughtErrorType()) { if (thrownError->isNever()) return std::nullopt; return thrownError; } // If we haven't computed the error type yet, return 'any Error'. return ctx.getErrorExistentialType(); } auto tryExpr = get(); if (auto forceTry = llvm::dyn_cast(tryExpr)) { if (auto thrownError = forceTry->getThrownError()) return thrownError; // If we haven't computed the error type yet, return 'any Error'. return ctx.getErrorExistentialType(); } if (auto optTry = llvm::dyn_cast(tryExpr)) { if (auto thrownError = optTry->getThrownError()) return thrownError; // If we haven't computed the error type yet, return 'any Error'. return ctx.getErrorExistentialType(); } llvm_unreachable("Unhandled catch node kind"); } Type CatchNode::getExplicitCaughtType(ASTContext &ctx) const { return evaluateOrDefault( ctx.evaluator, ExplicitCaughtTypeRequest{&ctx, *this}, Type()); } void swift::simple_display(llvm::raw_ostream &out, CatchNode catchNode) { out << "catch node"; } SourceLoc swift::extractNearestSourceLoc(CatchNode catchNode) { if (auto func = catchNode.dyn_cast()) return func->getLoc(); if (auto closure = catchNode.dyn_cast()) return closure->getLoc(); if (auto doCatch = catchNode.dyn_cast()) return doCatch->getDoLoc(); if (auto tryExpr = catchNode.dyn_cast()) return tryExpr->getTryLoc(); llvm_unreachable("Unhandled catch node"); } //----------------------------------------------------------------------------// // ExplicitCaughtTypeRequest computation. //----------------------------------------------------------------------------// bool ExplicitCaughtTypeRequest::isCached() const { auto catchNode = std::get<1>(getStorage()); // try? and try! never need to be cached. if (catchNode.is()) return false; // Functions with explicitly-written thrown types need the result cached. if (auto func = catchNode.dyn_cast()) { return func->ThrownType.getTypeRepr() != nullptr; } // Closures with explicitly-written thrown types need the result cached. if (auto closure = catchNode.dyn_cast()) { return closure->ThrownType != nullptr; } // Do..catch with explicitly-written thrown types need the result cached. if (auto doCatch = catchNode.dyn_cast()) { return doCatch->getThrowsLoc().isValid(); } llvm_unreachable("Unhandled catch node"); } std::optional ExplicitCaughtTypeRequest::getCachedResult() const { // Map a possibly-null Type to std::optional. auto nonnullTypeOrNone = [](Type type) -> std::optional { if (type.isNull()) return std::nullopt; return type; }; auto catchNode = std::get<1>(getStorage()); if (auto func = catchNode.dyn_cast()) { return nonnullTypeOrNone(func->ThrownType.getType()); } if (auto closure = catchNode.dyn_cast()) { if (closure->ThrownType) { return nonnullTypeOrNone(closure->ThrownType->getInstanceType()); } return std::nullopt; } if (auto doCatch = catchNode.dyn_cast()) { return nonnullTypeOrNone(doCatch->ThrownType.getType()); } llvm_unreachable("Unhandled catch node"); } void ExplicitCaughtTypeRequest::cacheResult(Type type) const { auto catchNode = std::get<1>(getStorage()); if (auto func = catchNode.dyn_cast()) { func->ThrownType.setType(type); return; } if (auto closure = catchNode.dyn_cast()) { if (closure->ThrownType) closure->ThrownType->setType(MetatypeType::get(type)); else closure->ThrownType = TypeExpr::createImplicit(type, type->getASTContext()); return; } if (auto doCatch = catchNode.dyn_cast()) { doCatch->ThrownType.setType(type); return; } llvm_unreachable("Unhandled catch node"); }