//===--- DeclContext.cpp - DeclContext implementation ---------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/AST/DeclContext.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/AccessScope.h" #include "swift/AST/AvailabilityConstraint.h" #include "swift/AST/AvailabilityContext.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/Expr.h" #include "swift/AST/FileUnit.h" #include "swift/AST/GenericEnvironment.h" #include "swift/AST/Initializer.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Module.h" #include "swift/AST/ParseRequests.h" #include "swift/AST/SourceFile.h" #include "swift/AST/TypeCheckRequests.h" #include "swift/AST/TypeRepr.h" #include "swift/AST/Types.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "swift/ClangImporter/ClangImporter.h" #include "clang/AST/ASTContext.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" using namespace swift; #define DEBUG_TYPE "Name lookup" STATISTIC(NumLazyIterableDeclContexts, "# of serialized iterable declaration contexts"); STATISTIC(NumUnloadedLazyIterableDeclContexts, "# of serialized iterable declaration contexts never loaded"); ASTContext &DeclContext::getASTContext() const { return getParentModule()->getASTContext(); } GenericTypeDecl *DeclContext::getSelfTypeDecl() const { auto decl = const_cast(getAsDecl()); if (!decl) return nullptr; auto ext = dyn_cast(decl); if (!ext) return dyn_cast(decl); return ext->getExtendedNominal(); } /// If this DeclContext is a NominalType declaration or an /// extension thereof, return the NominalTypeDecl. NominalTypeDecl *DeclContext::getSelfNominalTypeDecl() const { return dyn_cast_or_null(getSelfTypeDecl()); } ClassDecl *DeclContext::getSelfClassDecl() const { return dyn_cast_or_null(getSelfTypeDecl()); } EnumDecl *DeclContext::getSelfEnumDecl() const { return dyn_cast_or_null(getSelfTypeDecl()); } StructDecl *DeclContext::getSelfStructDecl() const { return dyn_cast_or_null(getSelfTypeDecl()); } ProtocolDecl *DeclContext::getSelfProtocolDecl() const { return dyn_cast_or_null(getSelfTypeDecl()); } ProtocolDecl *DeclContext::getExtendedProtocolDecl() const { if (auto decl = const_cast(getAsDecl())) if (auto ED = dyn_cast(decl)) return dyn_cast_or_null(ED->getExtendedNominal()); return nullptr; } VarDecl *DeclContext::getNonLocalVarDecl() const { if (auto *init = dyn_cast(this)) { if (auto binding = init->getBinding()) { if (auto *var = binding->getAnchoringVarDecl(init->getBindingIndex())) { return var; } } } return nullptr; } Type DeclContext::getDeclaredTypeInContext() const { if (auto declaredType = getDeclaredInterfaceType()) return mapTypeIntoContext(declaredType); return Type(); } Type DeclContext::getDeclaredInterfaceType() const { if (auto *ED = dyn_cast(this)) { auto *NTD = ED->getExtendedNominal(); if (NTD == nullptr) return ErrorType::get(ED->getASTContext()); return NTD->getDeclaredInterfaceType(); } if (auto *NTD = dyn_cast(this)) return NTD->getDeclaredInterfaceType(); return Type(); } void DeclContext::forEachGenericContext( llvm::function_ref fn) const { auto dc = this; do { if (auto decl = dc->getAsDecl()) { // Extensions do not capture outer generic parameters. if (auto *ext = dyn_cast(decl)) { for (auto *gpList = ext->getGenericParams(); gpList != nullptr; gpList = gpList->getOuterParameters()) { fn(gpList); } return; } if (auto genericCtx = decl->getAsGenericContext()) if (auto *gpList = genericCtx->getGenericParams()) fn(gpList); // Protocols do not capture outer generic parameters. if (isa(decl)) return; } } while ((dc = dc->getParentForLookup())); } unsigned DeclContext::getGenericContextDepth() const { unsigned depth = -1; forEachGenericContext([&](GenericParamList *) { ++depth; }); return depth; } GenericSignature DeclContext::getGenericSignatureOfContext() const { auto dc = this; do { if (auto decl = dc->getAsDecl()) if (auto GC = decl->getAsGenericContext()) return GC->getGenericSignature(); } while ((dc = dc->getParent())); return nullptr; } GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const { auto dc = this; do { if (auto decl = dc->getAsDecl()) if (auto GC = decl->getAsGenericContext()) return GC->getGenericEnvironment(); } while ((dc = dc->getParent())); return nullptr; } Type DeclContext::mapTypeIntoContext(Type type) const { return GenericEnvironment::mapTypeIntoContext( getGenericEnvironmentOfContext(), type); } DeclContext *DeclContext::getLocalContext() { if (isLocalContext()) return this; if (isModuleContext()) return nullptr; return getParent()->getLocalContext(); } AbstractFunctionDecl *DeclContext::getInnermostMethodContext() { auto dc = this; do { if (auto decl = dc->getAsDecl()) { auto func = dyn_cast(decl); // If we found a non-func decl, we're done. if (func == nullptr) return nullptr; if (func->getDeclContext()->isTypeContext()) return func; } } while ((dc = dc->getParent())); return nullptr; } AccessorDecl *DeclContext::getInnermostPropertyAccessorContext() { auto dc = this; do { if (auto decl = dc->getAsDecl()) { auto accessor = dyn_cast(decl); // If we found a non-accessor decl, we're done. if (accessor == nullptr) return nullptr; auto *storage = accessor->getStorage(); if (isa(storage) && storage->getDeclContext()->isTypeContext()) return accessor; } } while ((dc = dc->getParent())); return nullptr; } bool DeclContext::isTypeContext() const { if (auto decl = getAsDecl()) return isa(decl) || isa(decl); return false; } DeclContext *DeclContext::getInnermostTypeContext() { auto dc = this; do { if (dc->isTypeContext()) return dc; } while ((dc = dc->getParent())); return nullptr; } Decl *DeclContext::getInnermostDeclarationDeclContext() { auto DC = this; do { if (auto decl = DC->getAsDecl()) return isa(decl) ? nullptr : decl; } while ((DC = DC->getParent())); return nullptr; } Decl *DeclContext::getTopmostDeclarationDeclContext() { auto *dc = this; Decl *topmost = nullptr; while (auto *decl = dc->getInnermostDeclarationDeclContext()) { topmost = decl; dc = decl->getDeclContext(); } return topmost; } DeclContext *DeclContext::getOutermostFunctionContext() { AbstractFunctionDecl *result = nullptr; auto dc = this; do { if (auto afd = dyn_cast(dc)) result = afd; // If we've found a non-local context, we don't have to keep walking up // the hierarchy. if (!dc->isLocalContext()) break; } while ((dc = dc->getParent())); return result; } DeclContext *DeclContext::getInnermostSkippedFunctionContext() { auto dc = this; do { if (auto afd = dyn_cast(dc)) if (afd->isBodySkipped()) return afd; } while ((dc = dc->getParent())); return nullptr; } ClosureExpr *DeclContext::getInnermostClosureForCaptures() { auto *DC = this; do { if (auto *CE = dyn_cast(DC)) return CE; // Autoclosures and AbstractFunctionDecls can propagate captures. switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: case DeclContextKind::AbstractFunctionDecl: continue; default: return nullptr; } } while ((DC = DC->getParent())); return nullptr; } DeclContext *DeclContext::getParentForLookup() const { if (isa(this)) { // If we are inside an extension, skip directly // to the module scope context, without looking at any (invalid) // outer types. return getModuleScopeContext(); } if (isUnsupportedNestedProtocol()) { // Protocols in generic contexts must not look in to their parents, // as the parents may contain types with inferred implicit // generic parameters not present in the protocol's generic signature. return getModuleScopeContext(); } if (isa(this)) { // If we are inside a nominal type that is inside a protocol, // skip the protocol. if (isa(getParent())) return getModuleScopeContext(); } return getParent(); } PackageUnit *DeclContext::getPackageContext(bool lookupIfNotCurrent) const { // Current decl context might be PackageUnit, which is not in the // DeclContext hierarchy, so check for it first if (isPackageContext()) return const_cast(cast(this)); // If the current context is not PackageUnit, look it up via // the parent module if needed if (lookupIfNotCurrent) { auto mdecl = getParentModule(); return mdecl->getPackage(); } return nullptr; } ModuleDecl *DeclContext::getParentModule() const { // If the current context is PackageUnit, return the module // decl context pointing to the current context. This check // needs to be done first as PackageUnit is not in the DeclContext // hierarchy. if (auto pkg = getPackageContext()) { auto &mdecl = pkg->getSourceModule(); return &mdecl; } const DeclContext *DC = this; while (!DC->isModuleContext()) DC = DC->getParent(); return const_cast(cast(DC)); } SourceFile *DeclContext::getParentSourceFile() const { const DeclContext *DC = this; SourceLoc loc; while (DC && !DC->isModuleScopeContext()) { // If we don't have a source location yet, try to grab one from this // context. if (loc.isInvalid()) { switch (DC->getContextKind()) { case DeclContextKind::AbstractClosureExpr: loc = cast(DC)->getLoc(); break; case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::EnumElementDecl: case DeclContextKind::ExtensionDecl: case DeclContextKind::GenericTypeDecl: case DeclContextKind::MacroDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::TopLevelCodeDecl: loc = DC->getAsDecl()->getLoc(/*SerializedOK=*/false); break; case DeclContextKind::Initializer: case DeclContextKind::FileUnit: case DeclContextKind::Module: case DeclContextKind::Package: case DeclContextKind::SerializedAbstractClosure: case DeclContextKind::SerializedTopLevelCodeDecl: break; } } DC = DC->getParent(); } if (!DC) return nullptr; auto fallbackSF = const_cast(dyn_cast(DC)); if (auto module = DC->getParentModule()) { if (auto sf = module->getSourceFileContainingLocation(loc)) return sf; } return fallbackSF; } SourceFile *DeclContext::getOutermostParentSourceFile() const { auto sf = getParentSourceFile(); if (!sf) return nullptr; // Find the originating source file. while (auto enclosingSF = sf->getEnclosingSourceFile()) sf = enclosingSF; return sf; } bool DeclContext::isInSwiftinterface() const { auto sf = getParentSourceFile(); return sf && sf->Kind == SourceFileKind::Interface; } DeclContext *DeclContext::getModuleScopeContext() const { // If the current context is PackageUnit, return the module // decl context pointing to the current context. This check // needs to be done first as PackageUnit is not in the DeclContext // hierarchy. if (auto pkg = getPackageContext()) { auto &mdecl = pkg->getSourceModule(); return &mdecl; } auto DC = const_cast(this); while (true) { if (DC->ParentAndKind.getInt() == ASTHierarchy::FileUnit) return DC; if (auto NextDC = DC->getParent()) { DC = NextDC; } else { assert(DC && isa(DC->getAsDecl()) && "no module decl context found!"); return DC; } } } void DeclContext::getSeparatelyImportedOverlays( ModuleDecl *declaring, SmallVectorImpl &overlays) const { if (auto SF = getOutermostParentSourceFile()) SF->getSeparatelyImportedOverlays(declaring, overlays); } /// Determine whether the given context is generic at any level. bool DeclContext::isGenericContext() const { auto dc = this; do { if (auto decl = dc->getAsDecl()) { if (auto GC = decl->getAsGenericContext()) { if (GC->getGenericParams()) return true; } } } while ((dc = dc->getParentForLookup())); return false; } ResilienceExpansion DeclContext::getResilienceExpansion() const { auto fragileKind = getFragileFunctionKind(); switch (fragileKind.kind) { case FragileFunctionKind::Transparent: case FragileFunctionKind::Inlinable: case FragileFunctionKind::AlwaysEmitIntoClient: case FragileFunctionKind::DefaultArgument: case FragileFunctionKind::PropertyInitializer: case FragileFunctionKind::BackDeploy: return ResilienceExpansion::Minimal; case FragileFunctionKind::None: return ResilienceExpansion::Maximal; } llvm_unreachable("Bad fragile function kind"); } FragileFunctionKind DeclContext::getFragileFunctionKind() const { auto &context = getASTContext(); return evaluateOrDefault( context.evaluator, FragileFunctionKindRequest{const_cast(this)}, {FragileFunctionKind::None}); } FragileFunctionKind swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator, DeclContext *context) const { for (const auto *dc = context->getLocalContext(); dc && dc->isLocalContext(); dc = dc->getParent()) { // Default argument initializer contexts have their resilience expansion // set when they're type checked. if (isa(dc)) { dc = dc->getParent(); auto *VD = cast(dc->getAsDecl()); ASSERT(VD->hasParameterList()); if (VD->getDeclContext()->isLocalContext()) { auto kind = VD->getDeclContext()->getFragileFunctionKind(); if (kind.kind != FragileFunctionKind::None) return {FragileFunctionKind::DefaultArgument}; } auto effectiveAccess = VD->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); if (effectiveAccess.isPublic()) { return {FragileFunctionKind::DefaultArgument}; } return {FragileFunctionKind::None}; } // Stored property initializer contexts use minimal resilience expansion // if the type is formally fixed layout. if (auto *init = dyn_cast (dc)) { auto bindingIndex = init->getBindingIndex(); if (auto *varDecl = init->getBinding()->getAnchoringVarDecl(bindingIndex)) { if (varDecl->isInitExposedToClients()) { return {FragileFunctionKind::PropertyInitializer}; } } return {FragileFunctionKind::None}; } if (auto *AFD = dyn_cast(dc)) { // If the function is a nested function, we will serialize its body if // we serialize the parent's body. if (AFD->getDeclContext()->isLocalContext()) continue; auto funcAccess = AFD->getFormalAccessScope(/*useDC=*/nullptr, /*treatUsableFromInlineAsPublic=*/true); // If the function is not externally visible, we will not be serializing // its body. if (!funcAccess.isPublic()) { return {FragileFunctionKind::None}; } // If the function is public, @_transparent implies @inlinable. if (AFD->isTransparent()) { return {FragileFunctionKind::Transparent}; } if (AFD->getAttrs().hasAttribute()) { return {FragileFunctionKind::Inlinable}; } if (AFD->getAttrs().hasAttribute()) { return {FragileFunctionKind::AlwaysEmitIntoClient}; } if (AFD->isBackDeployed()) { return {FragileFunctionKind::BackDeploy}; } // Property and subscript accessors inherit @_alwaysEmitIntoClient, // @backDeployed, and @inlinable from their storage declarations. if (auto accessor = dyn_cast(AFD)) { auto *storage = accessor->getStorage(); if (storage->getAttrs().getAttribute()) { return {FragileFunctionKind::Inlinable}; } if (storage->getAttrs().hasAttribute()) { return {FragileFunctionKind::AlwaysEmitIntoClient}; } if (storage->isBackDeployed()) { return {FragileFunctionKind::BackDeploy}; } } } } return {FragileFunctionKind::None}; } /// Determine whether the innermost context is generic. bool DeclContext::isInnermostContextGeneric() const { if (auto Decl = getAsDecl()) if (auto GC = Decl->getAsGenericContext()) return GC->isGeneric(); return false; } unsigned DeclContext::getSyntacticDepth() const { // Module scope == depth 0. if (isModuleScopeContext()) return 0; return 1 + getParent()->getSyntacticDepth(); } unsigned DeclContext::getSemanticDepth() const { // For extensions, count the depth of the nominal type being extended. if (isa(this)) { if (auto nominal = getSelfNominalTypeDecl()) return nominal->getSemanticDepth(); return 1; } // Module scope == depth 0. if (isModuleScopeContext()) return 0; return 1 + getParent()->getSemanticDepth(); } bool DeclContext::mayContainMembersAccessedByDynamicLookup() const { // Members of non-generic classes and class extensions can be found by /// dynamic lookup. if (auto *CD = getSelfClassDecl()) return !CD->isGenericContext(); // Members of @objc protocols (but not protocol extensions) can be // found by dynamic lookup. if (auto *PD = dyn_cast(this)) return PD->getAttrs().hasAttribute(); return false; } bool DeclContext::canBeParentOfExtension() const { return isa(this); } bool DeclContext::walkContext(ASTWalker &Walker) { switch (getContextKind()) { case DeclContextKind::Package: return false; case DeclContextKind::Module: return cast(this)->walk(Walker); case DeclContextKind::FileUnit: return cast(this)->walk(Walker); case DeclContextKind::AbstractClosureExpr: return cast(this)->walk(Walker); case DeclContextKind::GenericTypeDecl: return cast(this)->walk(Walker); case DeclContextKind::ExtensionDecl: return cast(this)->walk(Walker); case DeclContextKind::TopLevelCodeDecl: return cast(this)->walk(Walker); case DeclContextKind::AbstractFunctionDecl: return cast(this)->walk(Walker); case DeclContextKind::SubscriptDecl: return cast(this)->walk(Walker); case DeclContextKind::EnumElementDecl: return cast(this)->walk(Walker); case DeclContextKind::MacroDecl: return cast(this)->walk(Walker); case DeclContextKind::SerializedAbstractClosure: case DeclContextKind::SerializedTopLevelCodeDecl: llvm_unreachable("walk is unimplemented for deserialized contexts"); case DeclContextKind::Initializer: // Is there any point in trying to walk the expression? return false; } llvm_unreachable("bad DeclContextKind"); } void DeclContext::dumpContext() const { printContext(llvm::errs()); } void AccessScope::dump() const { llvm::errs() << getAccessLevelSpelling(accessLevelForDiagnostics()) << ": "; if (isPublic() || isPackage()) { llvm::errs() << "(null)\n"; return; } if (auto *file = dyn_cast(getDeclContext())) { llvm::errs() << "file '" << file->getFilename() << "'\n"; return; } if (auto *decl = getDeclContext()->getAsDecl()) { llvm::errs() << Decl::getKindName(decl->getKind()) << " "; if (auto *ext = dyn_cast(decl)) { auto *extended = ext->getExtendedNominal(); if (extended) llvm::errs() << extended->getName(); else llvm::errs() << "(null)"; } else if (auto *named = dyn_cast(decl)) { llvm::errs() << named->getName(); } else { llvm::errs() << (const void *)decl; } SourceLoc loc = decl->getLoc(); if (loc.isValid()) { llvm::errs() << " at "; loc.print(llvm::errs(), decl->getASTContext().SourceMgr); } llvm::errs() << "\n"; return; } // If all else fails, dump the DeclContext tree. getDeclContext()->printContext(llvm::errs()); } template static unsigned getLineNumber(DCType *DC) { SourceLoc loc = DC->getLoc(); if (loc.isInvalid()) return 0; const ASTContext &ctx = static_cast(DC)->getASTContext(); return ctx.SourceMgr.getPresumedLineAndColumnForLoc(loc).first; } unsigned DeclContext::printContext(raw_ostream &OS, const unsigned indent, const bool onlyAPartialLine) const { unsigned Depth = 0; if (!onlyAPartialLine) if (auto *P = getParent()) Depth = P->printContext(OS, indent); const char *Kind; switch (getContextKind()) { case DeclContextKind::Package: Kind = "Package"; break; case DeclContextKind::Module: Kind = "Module"; break; case DeclContextKind::FileUnit: Kind = "FileUnit"; break; case DeclContextKind::AbstractClosureExpr: Kind = "AbstractClosureExpr"; break; case DeclContextKind::SerializedAbstractClosure: Kind = "SerializedAbstractClosure"; break; case DeclContextKind::GenericTypeDecl: switch (cast(this)->getKind()) { #define DECL(ID, PARENT) \ case DeclKind::ID: Kind = #ID "Decl"; break; #include "swift/AST/DeclNodes.def" } break; case DeclContextKind::ExtensionDecl: Kind = "ExtensionDecl"; break; case DeclContextKind::TopLevelCodeDecl: Kind = "TopLevelCodeDecl"; break; case DeclContextKind::SerializedTopLevelCodeDecl: Kind = "SerializedTopLevelCodeDecl"; break; case DeclContextKind::Initializer: Kind = "Initializer"; break; case DeclContextKind::AbstractFunctionDecl: Kind = "AbstractFunctionDecl"; break; case DeclContextKind::SubscriptDecl: Kind = "SubscriptDecl"; break; case DeclContextKind::EnumElementDecl: Kind = "EnumElementDecl"; break; case DeclContextKind::MacroDecl: Kind = "MacroDecl"; break; } OS.indent(Depth * 2 + indent) << static_cast(this) << " " << Kind; switch (getContextKind()) { case DeclContextKind::Package: OS << " name=" << cast(this)->getName(); break; case DeclContextKind::Module: OS << " name=" << cast(this)->getName(); break; case DeclContextKind::FileUnit: switch (cast(this)->getKind()) { case FileUnitKind::Builtin: OS << " Builtin"; break; case FileUnitKind::Source: OS << " file=\"" << cast(this)->getFilename() << "\""; break; case FileUnitKind::Synthesized: OS << " synthesized file"; break; case FileUnitKind::SerializedAST: case FileUnitKind::ClangModule: case FileUnitKind::DWARFModule: OS << " file=\"" << cast(this)->getFilename() << "\""; break; } break; case DeclContextKind::AbstractClosureExpr: OS << " line=" << getLineNumber(cast(this)); OS << " : " << cast(this)->getType(); break; case DeclContextKind::SerializedAbstractClosure: { OS << " : " << cast(this)->getType(); break; } case DeclContextKind::GenericTypeDecl: OS << " name=" << cast(this)->getName(); break; case DeclContextKind::ExtensionDecl: { auto *ED = cast(this); OS << " line=" << getLineNumber(ED); OS << " base="; if (ED->hasBeenBound()) { OS << ED->getExtendedType(); } else { ED->getExtendedTypeRepr()->print(OS); } break; } case DeclContextKind::TopLevelCodeDecl: OS << " line=" << getLineNumber(cast(this)); break; case DeclContextKind::SerializedTopLevelCodeDecl: // Already printed the kind, nothing else to do. break; case DeclContextKind::AbstractFunctionDecl: { auto *AFD = cast(this); OS << " name="; if (auto *AD = dyn_cast(AFD)) { OS << accessorKindName(AD->getAccessorKind()); } else { OS << AFD->getName(); } if (AFD->hasInterfaceType()) OS << " : " << AFD->getInterfaceType(); else OS << " : (no type set)"; break; } case DeclContextKind::SubscriptDecl: { auto *SD = cast(this); OS << " name=" << SD->getBaseName(); if (SD->hasInterfaceType()) OS << " : " << SD->getInterfaceType(); else OS << " : (no type set)"; break; } case DeclContextKind::EnumElementDecl: { auto *EED = cast(this); OS << " name=" << EED->getBaseName(); if (EED->hasInterfaceType()) OS << " : " << EED->getInterfaceType(); else OS << " : (no type set)"; break; } case DeclContextKind::MacroDecl: { auto *MD = cast(this); OS << " name=" << MD->getBaseName(); if (MD->hasInterfaceType()) OS << " : " << MD->getInterfaceType(); else OS << " : (no type set)"; break; } case DeclContextKind::Initializer: switch (cast(this)->getInitializerKind()) { case InitializerKind::PatternBinding: { auto init = cast(this); OS << " PatternBinding 0x" << (void*) init->getBinding() << " #" << init->getBindingIndex(); break; } case InitializerKind::DefaultArgument: { auto init = cast(this); OS << " DefaultArgument index=" << init->getIndex(); break; } case InitializerKind::PropertyWrapper: { auto init = cast(this); OS << "PropertyWrapper 0x" << (void*)init->getWrappedVar() << ", kind="; switch (init->getKind()) { case PropertyWrapperInitializer::Kind::WrappedValue: OS << "wrappedValue"; break; case PropertyWrapperInitializer::Kind::ProjectedValue: OS << "projectedValue"; break; } break; } case InitializerKind::CustomAttribute: OS << " CustomAttribute"; break; } break; } if (auto decl = getAsDecl()) if (decl->getClangNode().getLocation().isValid()) { auto &clangSM = getASTContext().getClangModuleLoader() ->getClangASTContext().getSourceManager(); OS << " clang_loc="; decl->getClangNode().getLocation().print(OS, clangSM); } if (!onlyAPartialLine) OS << "\n"; return Depth + 1; } const Decl * IterableDeclContext::getDecl() const { switch (getIterableContextKind()) { case IterableDeclContextKind::NominalTypeDecl: return cast(this); break; case IterableDeclContextKind::ExtensionDecl: return cast(this); break; } llvm_unreachable("Unhandled IterableDeclContextKind in switch."); } GenericContext *IterableDeclContext::getAsGenericContext() { switch (getIterableContextKind()) { case IterableDeclContextKind::NominalTypeDecl: return cast(this); case IterableDeclContextKind::ExtensionDecl: return cast(this); } llvm_unreachable("Unhandled IterableDeclContextKind in switch."); } ASTContext &IterableDeclContext::getASTContext() const { return getDecl()->getASTContext(); } SourceRange IterableDeclContext::getBraces() const { switch (getIterableContextKind()) { case IterableDeclContextKind::NominalTypeDecl: return cast(this)->getBraces(); break; case IterableDeclContextKind::ExtensionDecl: return cast(this)->getBraces(); break; } } DeclRange IterableDeclContext::getCurrentMembersWithoutLoading() const { return DeclRange(FirstDeclAndLazyMembers.getPointer(), nullptr); } DeclRange IterableDeclContext::getMembers() const { return getCurrentMembers(); } DeclRange IterableDeclContext::getCurrentMembers() const { loadAllMembers(); return getCurrentMembersWithoutLoading(); } ArrayRef IterableDeclContext::getParsedMembers() const { ASTContext &ctx = getASTContext(); auto mutableThis = const_cast(this); return evaluateOrDefault( ctx.evaluator, ParseMembersRequest{mutableThis}, FingerprintAndMembers()) .members; } ArrayRef IterableDeclContext::getABIMembers() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, ABIMembersRequest{const_cast(this)}, ArrayRef()); } ArrayRef IterableDeclContext::getAllMembers() const { ASTContext &ctx = getASTContext(); return evaluateOrDefault( ctx.evaluator, AllMembersRequest{const_cast(this)}, ArrayRef()); } void IterableDeclContext::addMemberPreservingSourceOrder(Decl *member) { auto &SM = getASTContext().SourceMgr; SourceLoc start = member->getStartLoc(); Decl *hint = nullptr; for (auto *existingMember : getMembers()) { if (existingMember->isImplicit()) continue; // An EnumCaseDecl contains one or more EnumElementDecls, // but the EnumElementDecls are also added as members of // the parent enum. We ignore the EnumCaseDecl since its // source range overlaps with that of the EnumElementDecls. if (isa(existingMember)) continue; if (!SM.isBeforeInBuffer(existingMember->getEndLoc(), start)) break; hint = existingMember; } addMember(member, hint, /*insertAtHead=*/hint == nullptr); } /// Add a member to this context. void IterableDeclContext::addMember(Decl *member, Decl *hint, bool insertAtHead) { // Add the member to the list of declarations without notification. addMemberSilently(member, hint, insertAtHead); // Notify our parent declaration that we have added the member, which can // be used to update the lookup tables. switch (getIterableContextKind()) { case IterableDeclContextKind::NominalTypeDecl: { auto nominal = cast(this); nominal->addedMember(member); assert(member->getDeclContext() == nominal && "Added member to the wrong context"); break; } case IterableDeclContextKind::ExtensionDecl: { auto ext = cast(this); ext->addedMember(member); assert(member->getDeclContext() == ext && "Added member to the wrong context"); break; } } } void IterableDeclContext::addMemberSilently(Decl *member, Decl *hint, bool insertAtHead) const { assert(!isa(member) && "Accessors should not be added here"); assert(!member->NextDecl && "Already added to a container"); #ifndef NDEBUG // Assert that new declarations are always added in source order. auto checkSourceRange = [&](Decl *prev, Decl *next) { // SKip these checks for imported and deserialized decls. if (!member->getDeclContext()->getParentSourceFile()) return; auto shouldSkip = [](Decl *d) { // PatternBindingDecl source ranges overlap with VarDecls and // EnumCaseDecl source ranges overlap with EnumElementDecls. // Skip them all here to avoid spurious assertions. if (isa(d) || isa(d)) return true; // Ignore source location information of implicit declarations. if (d->isImplicit()) return true; // Imported decls won't have complete location info. if (d->hasClangNode()) return true; return false; }; if (shouldSkip(prev) || shouldSkip(next)) return; SourceLoc prevEnd = prev->getEndLoc(); SourceLoc nextStart = next->getStartLoc(); assert(prevEnd.isValid() && "Only implicit decls can have invalid source location"); assert(nextStart.isValid() && "Only implicit decls can have invalid source location"); if (getASTContext().SourceMgr.isAtOrBefore(prevEnd, nextStart)) return; llvm::errs() << "Source ranges out of order in addMember():\n"; prev->dump(llvm::errs()); next->dump(llvm::errs()); abort(); }; #endif // Empty list. if (!FirstDeclAndLazyMembers.getPointer()) { assert(hint == nullptr); FirstDeclAndLazyMembers.setPointer(member); LastDeclAndKind.setPointer(member); // Insertion at the head. } else if (insertAtHead) { assert(hint == nullptr); member->NextDecl = FirstDeclAndLazyMembers.getPointer(); FirstDeclAndLazyMembers.setPointer(member); // Insertion at the tail. } else if (hint == nullptr) { auto *last = LastDeclAndKind.getPointer(); #ifndef NDEBUG checkSourceRange(last, member); #endif last->NextDecl = member; LastDeclAndKind.setPointer(member); // Insertion after 'hint' (which may be the tail). } else { #ifndef NDEBUG checkSourceRange(hint, member); #endif member->NextDecl = hint->NextDecl; hint->NextDecl = member; // Handle case where the 'hint' is the tail. if (LastDeclAndKind.getPointer() == hint) LastDeclAndKind.setPointer(member); } } void IterableDeclContext::setMemberLoader(LazyMemberLoader *loader, uint64_t contextData) { assert(!hasLazyMembers() && "already have lazy members"); ASTContext &ctx = getASTContext(); auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, loader); FirstDeclAndLazyMembers.setInt(true); contextInfo->memberData = contextData; ++NumLazyIterableDeclContexts; ++NumUnloadedLazyIterableDeclContexts; // FIXME: (transitional) increment the redundant "always-on" counter. if (auto s = ctx.Stats) { ++s->getFrontendCounters().NumLazyIterableDeclContexts; ++s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts; } } bool IterableDeclContext::hasUnparsedMembers() const { if (AddedParsedMembers) return false; if (!getAsGenericContext()->getParentSourceFile()) { // There will never be any parsed members to add, so set the flag to say // we are done so we can short-circuit next time. const_cast(this)->AddedParsedMembers = 1; return false; } return true; } void IterableDeclContext::setHasLazyMembers(bool hasLazyMembers) const { FirstDeclAndLazyMembers.setInt(hasLazyMembers); } void IterableDeclContext::loadAllMembers() const { ASTContext &ctx = getASTContext(); // For contexts within a source file, get the list of parsed members. if (getAsGenericContext()->getParentSourceFile()) { // Retrieve the parsed members. Even if we've already added the parsed // members to this context, this call is important for recording the // dependency edge. auto mutableThis = const_cast(this); auto members = getParsedMembers(); // If we haven't already done so, add these members to this context. if (!AddedParsedMembers) { mutableThis->AddedParsedMembers = 1; for (auto member : members) { mutableThis->addMember(member); } } } if (!hasLazyMembers()) return; // Don't try to load all members re-entrant-ly. setHasLazyMembers(false); const Decl *container = getDecl(); auto contextInfo = ctx.getOrCreateLazyIterableContextData(this, /*lazyLoader=*/nullptr); contextInfo->loader->loadAllMembers(const_cast(container), contextInfo->memberData); --NumUnloadedLazyIterableDeclContexts; // FIXME: (transitional) decrement the redundant "always-on" counter. if (auto s = ctx.Stats) --s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts; } // Checks whether members of this decl and their respective member decls // (recursively) were deserialized into another module correctly, and // emits a diagnostic if deserialization failed. Requires the other module // module and this decl's module are in the same package, and this // decl's module has package optimization enabled. void IterableDeclContext::checkDeserializeMemberErrorInPackage(ModuleDecl *accessingModule) { // For decls in the same module, we can skip deserialization error checks. if (getDecl()->getModuleContext() == accessingModule) return; // Only check if accessing module is in the same package as this // decl's module, which has package optimization enabled. if (!getDecl()->getModuleContext()->inSamePackage(accessingModule) || !getDecl()->getModuleContext()->isResilient() || !getDecl()->getModuleContext()->serializePackageEnabled()) return; // Bail if already checked for an error. if (checkedForDeserializeMemberError()) return; // If members were not deserialized, force load here. if (!didDeserializeMembers()) { // This needs to be set to force load all members if not done already. setHasLazyMembers(true); // Calling getMembers actually loads the members. (void)getMembers(); assert(!hasLazyMembers()); assert(didDeserializeMembers()); } // Members could have been deserialized from other flows. Check // for an error here. First mark this decl 'checked' to prevent // infinite recursion in case of self-referencing members. setCheckedForDeserializeMemberError(true); // If members are already loaded above or by other flows, // calling getMembers here should be inexpensive. auto memberList = getMembers(); // This decl contains a member deserialization error; emit a diag. if (hasDeserializeMemberError()) { auto containerID = Identifier(); if (auto container = dyn_cast(getDecl())) { containerID = container->getBaseIdentifier(); } auto diagID = diag::cannot_bypass_resilience_due_to_missing_member_warn; if (getASTContext().LangOpts.AbortOnDeserializationFailForPackageCMO) diagID = diag::cannot_bypass_resilience_due_to_missing_member; auto foundMissing = false; for (auto member: memberList) { // Only storage vars can affect memory layout so // look up pattern binding decl or var decl. if (auto *PBD = dyn_cast(member)) { // If this pattern binding decl is empty, we have // a missing member. if (PBD->getNumPatternEntries() == 0) foundMissing = true; } // Check if a member can be cast to MissingMemberDecl. if (auto missingMember = dyn_cast(member)) { if (!missingMember->getName().getBaseName().isSpecial() && foundMissing) { foundMissing = false; auto missingMemberID = missingMember->getName().getBaseIdentifier(); getASTContext().Diags.diagnose(member->getLoc(), diagID, missingMemberID, missingMemberID.empty(), containerID, getDecl()->getModuleContext()->getBaseIdentifier(), accessingModule->getBaseIdentifier()); continue; } } // If not handled above, emit a diag here. if (foundMissing) { getASTContext().Diags.diagnose(getDecl()->getLoc(), diagID, Identifier(), true, containerID, getDecl()->getModuleContext()->getBaseIdentifier(), accessingModule->getBaseIdentifier()); } } } else { // This decl does not contain a member deserialization error. // Check for members of this decl's members recursively to // see if a member deserialization failed. for (auto member: memberList) { // Only storage vars can affect memory layout so // look up pattern binding decl or var decl. if (auto *PBD = dyn_cast(member)) { for (auto i : range(PBD->getNumPatternEntries())) { auto pattern = PBD->getPattern(i); pattern->forEachVariable([&](const VarDecl *VD) { // Bail if the var is static or has no storage if (VD->isStatic() || !VD->hasStorageOrWrapsStorage()) return; // Unwrap in case this var is optional. auto varType = VD->getInterfaceType()->getCanonicalType(); if (auto unwrapped = varType->getCanonicalType()->getOptionalObjectType()) { varType = unwrapped->getCanonicalType(); } // Handle BoundGenericType, e.g. [Foo: Bar], Dictionary. // Check for its arguments types, i.e. Foo, Bar. if (auto boundGeneric = varType->getAs()) { for (auto arg : boundGeneric->getGenericArgs()) { if (auto argNominal = arg->getNominalOrBoundGenericNominal()) { if (auto argIDC = dyn_cast(argNominal)) { argIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); if (argIDC->hasDeserializeMemberError()) { setHasDeserializeMemberError(true); break; } } } } } else if (auto tupleType = varType->getAs()) { // Handle TupleType, e.g. (Foo, Var). for (auto element : tupleType->getElements()) { if (auto elementNominal = element.getType()->getNominalOrBoundGenericNominal()) { if (auto elementIDC = dyn_cast(elementNominal)) { elementIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); if (elementIDC->hasDeserializeMemberError()) { setHasDeserializeMemberError(true); break; } } } } } else if (auto varNominal = varType->getNominalOrBoundGenericNominal()) { if (auto varIDC = dyn_cast(varNominal)) { varIDC->checkDeserializeMemberErrorInPackage(getDecl()->getModuleContext()); if (varIDC->hasDeserializeMemberError()) { setHasDeserializeMemberError(true); } } } }); } } } } } bool IterableDeclContext::wasDeserialized() const { const DeclContext *DC = getAsGenericContext(); if (auto F = dyn_cast(DC->getModuleScopeContext())) { return F->getKind() == FileUnitKind::SerializedAST; } return false; } bool IterableDeclContext::classof(const Decl *D) { switch (D->getKind()) { default: return false; #define DECL(ID, PARENT) // See previous line #define ITERABLE_DECL(ID, PARENT) \ case DeclKind::ID: return true; #include "swift/AST/DeclNodes.def" } } IterableDeclContext * IterableDeclContext::castDeclToIterableDeclContext(const Decl *D) { switch (D->getKind()) { default: llvm_unreachable("Decl is not a IterableDeclContext."); #define DECL(ID, PARENT) // See previous line #define ITERABLE_DECL(ID, PARENT) \ case DeclKind::ID: \ return const_cast( \ static_cast(cast(D))); #include "swift/AST/DeclNodes.def" } } std::optional IterableDeclContext::getBodyFingerprint() const { auto fileUnit = dyn_cast(getAsGenericContext()->getModuleScopeContext()); if (!fileUnit) return std::nullopt; if (isa(fileUnit)) { auto mutableThis = const_cast(this); return evaluateOrDefault(getASTContext().evaluator, ParseMembersRequest{mutableThis}, FingerprintAndMembers()) .fingerprint; } if (getDecl()->isImplicit()) return std::nullopt; return fileUnit->loadFingerprint(this); } /// Return the DeclContext to compare when checking private access in /// Swift 4 mode. The context returned is the type declaration if the context /// and the type declaration are in the same file, otherwise it is the types /// last extension in the source file. If the context does not refer to a /// declaration or extension, the supplied context is returned. static const DeclContext * getPrivateDeclContext(const DeclContext *DC, const SourceFile *useSF) { auto NTD = DC->getSelfNominalTypeDecl(); if (!NTD) return DC; // use the type declaration as the private scope if it is in the same // file as useSF. This occurs for both extensions and declarations. if (NTD->getOutermostParentSourceFile() == useSF) return NTD; // Otherwise use the last extension declaration in the same file. const DeclContext *lastExtension = nullptr; for (ExtensionDecl *ED : NTD->getExtensions()) if (ED->getOutermostParentSourceFile() == useSF) lastExtension = ED; // If there's no last extension, return the supplied context. return lastExtension ? lastExtension : DC; } AccessScope::AccessScope(const DeclContext *DC, bool isPrivate) : Value(DC, isPrivate) { if (isPrivate) { DC = getPrivateDeclContext(DC, DC->getOutermostParentSourceFile()); Value.setPointer(DC); } if (!DC || isa(DC) || isa(DC)) assert(!isPrivate && "public, package, or internal scope can't be private"); } bool AccessScope::isFileScope() const { auto DC = getDeclContext(); return DC && isa(DC); } bool AccessScope::isInternal() const { auto DC = getDeclContext(); return DC && isa(DC); } bool AccessScope::isPackage() const { auto DC = getDeclContext(); return DC && isa(DC); } AccessLevel AccessScope::accessLevelForDiagnostics() const { if (isPublic()) return AccessLevel::Public; if (isPackage()) return AccessLevel::Package; if (isa(getDeclContext())) return AccessLevel::Internal; if (getDeclContext()->isModuleScopeContext()) { return isPrivate() ? AccessLevel::Private : AccessLevel::FilePrivate; } return AccessLevel::Private; } bool AccessScope::allowsPrivateAccess(const DeclContext *useDC, const DeclContext *sourceDC) { // Check the lexical scope. if (useDC->isChildContextOf(sourceDC)) return true; // If the decl site has package acl, but the use site // has internal or less acl, check if it belongs to // the same package as the decl site's to allow access. if (auto srcPkg = sourceDC->getPackageContext()) { if (auto usePkg = useDC->getPackageContext(/*lookupIfNotCurrent*/ true)) { return usePkg->isSamePackageAs(srcPkg); } } // Do not allow access if the sourceDC does not represent a type. auto sourceNTD = sourceDC->getSelfNominalTypeDecl(); if (!sourceNTD) return false; // Do not allow access if the sourceDC is in a different file auto *useSF = useDC->getOutermostParentSourceFile(); if (useSF != sourceDC->getOutermostParentSourceFile()) { // sourceDC might be a C++ record with a SWIFT_PRIVATE_FILEID attribute, // which asks us to treat it as if it were defined in the file // with the specified FileID. auto clangDecl = sourceNTD->getDecl()->getClangDecl(); if (isa_and_nonnull(clangDecl)) { // Consider: class C { private: enum class E { M }; }; // If sourceDC is a C++ enum (e.g, E), then we are looking at one of its // members (e.g., E.M). If this is the case, then we should consider // the SWIFT_PRIVATE_FILEID of its enclosing class decl (e.g., C), if any. // Doing so allows the nested private enum's members to inherit the access // of the nested enum type itself. clangDecl = dyn_cast(clangDecl->getDeclContext()); sourceDC = sourceNTD->getDeclContext(); } if (!isa_and_nonnull(clangDecl)) return false; auto recordDecl = cast(clangDecl); // Diagnostics should enforce that there is at most SWIFT_PRIVATE_FILEID, // but this handles the case where there is more than anyway (whether that // is a feature or a bug). Allow access check to proceed if useSF is blessed // by any of the SWIFT_PRIVATE_FILEID annotations (i.e., disallow private // access if none of them bless useSF). if (!llvm::any_of( importer::getPrivateFileIDAttrs(recordDecl), [&](auto &blessed) { auto blessedFileID = SourceFile::FileIDStr::parse(blessed.first); return blessedFileID && blessedFileID->matches(useSF); })) { return false; } } // Compare the private scopes and iterate over the parent types. sourceDC = getPrivateDeclContext(sourceDC, useSF); while (!useDC->isModuleContext()) { useDC = getPrivateDeclContext(useDC, useSF); if (useDC == sourceDC) return true; // Get the parent type. If the context represents a type, look at the types // declaring context instead of the contexts parent. This will crawl up // the type hierarchy in nested extensions correctly. if (auto NTD = useDC->getSelfNominalTypeDecl()) useDC = NTD->getDeclContext(); else useDC = useDC->getParent(); } return false; } DeclContext *Decl::getDeclContextForModule() const { if (auto module = dyn_cast(this)) return const_cast(module); return nullptr; } DeclContextKind DeclContext::getContextKind() const { switch (ParentAndKind.getInt()) { case ASTHierarchy::Expr: return DeclContextKind::AbstractClosureExpr; case ASTHierarchy::Initializer: return DeclContextKind::Initializer; case ASTHierarchy::SerializedAbstractClosure: return DeclContextKind::SerializedAbstractClosure; case ASTHierarchy::SerializedTopLevelCodeDecl: return DeclContextKind::SerializedTopLevelCodeDecl; case ASTHierarchy::FileUnit: return DeclContextKind::FileUnit; case ASTHierarchy::Package: return DeclContextKind::Package; case ASTHierarchy::Decl: { auto decl = reinterpret_cast(this + 1); if (isa(decl)) return DeclContextKind::AbstractFunctionDecl; if (isa(decl)) return DeclContextKind::GenericTypeDecl; switch (decl->getKind()) { case DeclKind::Module: return DeclContextKind::Module; case DeclKind::TopLevelCode: return DeclContextKind::TopLevelCodeDecl; case DeclKind::Subscript: return DeclContextKind::SubscriptDecl; case DeclKind::EnumElement: return DeclContextKind::EnumElementDecl; case DeclKind::Extension: return DeclContextKind::ExtensionDecl; case DeclKind::Macro: return DeclContextKind::MacroDecl; default: llvm_unreachable("Unhandled Decl kind"); } } } llvm_unreachable("Unhandled DeclContext ASTHierarchy"); } bool DeclContext::hasValueSemantics() const { if (getExtendedProtocolDecl()) return !isClassConstrainedProtocolExtension(); return !getDeclaredInterfaceType()->hasReferenceSemantics(); } bool DeclContext::isClassConstrainedProtocolExtension() const { if (getExtendedProtocolDecl()) { auto ED = cast(this); if (auto sig = ED->getGenericSignature()) { return sig->requiresClass(ED->getSelfInterfaceType()); } } return false; } bool DeclContext::isAsyncContext() const { switch (getContextKind()) { case DeclContextKind::Initializer: case DeclContextKind::EnumElementDecl: case DeclContextKind::ExtensionDecl: case DeclContextKind::SerializedAbstractClosure: case DeclContextKind::SerializedTopLevelCodeDecl: case DeclContextKind::Package: case DeclContextKind::Module: case DeclContextKind::GenericTypeDecl: case DeclContextKind::MacroDecl: return false; case DeclContextKind::FileUnit: if (const SourceFile *sf = dyn_cast(this)) return sf->isAsyncTopLevelSourceFile(); return false; case DeclContextKind::TopLevelCodeDecl: return getParent()->isAsyncContext(); case DeclContextKind::AbstractClosureExpr: return cast(this)->isBodyAsync(); case DeclContextKind::AbstractFunctionDecl: return cast(this)->hasAsync(); case DeclContextKind::SubscriptDecl: return cast(this)->isAsync(); } llvm_unreachable("Unhandled DeclContextKind switch"); } SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) { assert(dc && "Expected non-null DeclContext!"); switch (dc->getContextKind()) { case DeclContextKind::Package: case DeclContextKind::Module: return SourceLoc(); case DeclContextKind::AbstractFunctionDecl: case DeclContextKind::EnumElementDecl: case DeclContextKind::ExtensionDecl: case DeclContextKind::GenericTypeDecl: case DeclContextKind::SubscriptDecl: case DeclContextKind::TopLevelCodeDecl: case DeclContextKind::MacroDecl: return extractNearestSourceLoc(dc->getAsDecl()); case DeclContextKind::AbstractClosureExpr: { SourceLoc loc = cast(dc)->getLoc(); if (loc.isValid()) return loc; return extractNearestSourceLoc(dc->getParent()); } case DeclContextKind::FileUnit: return SourceLoc(); case DeclContextKind::Initializer: case DeclContextKind::SerializedAbstractClosure: case DeclContextKind::SerializedTopLevelCodeDecl: return extractNearestSourceLoc(dc->getParent()); } llvm_unreachable("Unhandled DeclContextKindIn switch"); } #define DECL(Id, Parent) \ static_assert(!std::is_base_of::value, \ "Non-context Decl node has context?"); #define CONTEXT_DECL(Id, Parent) \ static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \ static_assert(std::is_base_of::value, \ "CONTEXT_DECL nodes must inherit from DeclContext"); #define CONTEXT_VALUE_DECL(Id, Parent) \ static_assert(alignof(DeclContext) == alignof(Id##Decl), "Alignment error"); \ static_assert(std::is_base_of::value, \ "CONTEXT_VALUE_DECL nodes must inherit from DeclContext"); #include "swift/AST/DeclNodes.def" #define EXPR(Id, Parent) \ static_assert(!std::is_base_of::value, \ "Non-context Expr node has context?"); #define CONTEXT_EXPR(Id, Parent) \ static_assert(alignof(DeclContext) == alignof(Id##Expr), "Alignment error"); \ static_assert(std::is_base_of::value, \ "CONTEXT_EXPR nodes must inherit from DeclContext"); #include "swift/AST/ExprNodes.def" #ifndef NDEBUG // XXX -- static_cast is not static enough for use with static_assert(). // DO verify this by temporarily breaking a Decl or Expr. // DO NOT assume that the compiler will emit this code blindly. SWIFT_CONSTRUCTOR static void verify_DeclContext_is_start_of_node() { auto decl = reinterpret_cast(0x1000 + sizeof(DeclContext)); #define DECL(Id, Parent) #define CONTEXT_DECL(Id, Parent) \ assert(reinterpret_cast(0x1000) == \ static_cast(decl)); #define CONTEXT_VALUE_DECL(Id, Parent) \ assert(reinterpret_cast(0x1000) == \ static_cast(decl)); #include "swift/AST/DeclNodes.def" auto expr = reinterpret_cast(0x1000 + sizeof(DeclContext)); #define EXPR(Id, Parent) #define CONTEXT_EXPR(Id, Parent) \ assert(reinterpret_cast(0x1000) == \ static_cast(expr)); #include "swift/AST/ExprNodes.def" } #endif void swift::simple_display(llvm::raw_ostream &out, const IterableDeclContext *idc) { simple_display(out, idc->getDecl()); } SourceLoc swift::extractNearestSourceLoc(const IterableDeclContext *idc) { return extractNearestSourceLoc(idc->getDecl()); } static bool isSpecializeExtensionContext(const DeclContext *dc) { if (dc->isModuleScopeContext()) return false; if (auto *extCtx = dyn_cast(dc)) { // and has specialized attr ... return extCtx->getAttrs().hasAttribute(); } auto *parentDecl = dc->getParent(); return isSpecializeExtensionContext(parentDecl); } bool DeclContext::isInSpecializeExtensionContext() const { return isSpecializeExtensionContext(this); } bool DeclContext::isUnsupportedNestedProtocol() const { return isa(this) && getParent()->isGenericContext(); } bool DeclContext::isAlwaysAvailableConformanceContext() const { auto *ext = dyn_cast(this); if (ext == nullptr) return true; // Check whether the extension is always available relative to the deployment // target. auto &ctx = getASTContext(); auto deploymentTarget = AvailabilityContext::forDeploymentTarget(ctx); auto constraints = getAvailabilityConstraintsForDecl(ext, deploymentTarget); return !constraints.getPrimaryConstraint(); }