Files
swift-mirror/lib/AST/DeclContext.cpp
Slava Pestov 769c4c1911 Sema: Fix some crashes with invalid nesting of extensions and protocols
Make sure we consistently use getParentForLookup() and not getParent()
when looking at generic DeclContexts. This is because an extension or
protocol that is nested inside of another generic context must never
inherit generic parameters from the parent context.

We already had this invariant enforced in some places, but now that we
do it more consistently we can fix more crashes of this kind.

Fixes <rdar://problem/58813746>, <https://bugs.swift.org/browse/SR-13004>.
2020-07-28 02:07:16 -04:00

1212 lines
38 KiB
C++

//===--- 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/AccessScope.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.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/Types.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/Statistic.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/SaveAndRestore.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");
// Only allow allocation of DeclContext using the allocator in ASTContext.
void *DeclContext::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) {
return C.Allocate(Bytes, Alignment);
}
ASTContext &DeclContext::getASTContext() const {
return getParentModule()->getASTContext();
}
GenericTypeDecl *DeclContext::getSelfTypeDecl() const {
auto decl = const_cast<Decl*>(getAsDecl());
if (!decl) return nullptr;
auto ext = dyn_cast<ExtensionDecl>(decl);
if (!ext) return dyn_cast<GenericTypeDecl>(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<NominalTypeDecl>(getSelfTypeDecl());
}
ClassDecl *DeclContext::getSelfClassDecl() const {
return dyn_cast_or_null<ClassDecl>(getSelfTypeDecl());
}
EnumDecl *DeclContext::getSelfEnumDecl() const {
return dyn_cast_or_null<EnumDecl>(getSelfTypeDecl());
}
StructDecl *DeclContext::getSelfStructDecl() const {
return dyn_cast_or_null<StructDecl>(getSelfTypeDecl());
}
ProtocolDecl *DeclContext::getSelfProtocolDecl() const {
return dyn_cast_or_null<ProtocolDecl>(getSelfTypeDecl());
}
ProtocolDecl *DeclContext::getExtendedProtocolDecl() const {
if (auto decl = const_cast<Decl*>(getAsDecl()))
if (auto ED = dyn_cast<ExtensionDecl>(decl))
return dyn_cast_or_null<ProtocolDecl>(ED->getExtendedNominal());
return nullptr;
}
GenericTypeParamType *DeclContext::getProtocolSelfType() const {
assert(getSelfProtocolDecl() && "not a protocol");
GenericParamList *genericParams;
if (auto proto = dyn_cast<ProtocolDecl>(this)) {
genericParams = proto->getGenericParams();
} else {
genericParams = cast<ExtensionDecl>(this)->getGenericParams();
}
if (genericParams == nullptr)
return nullptr;
return genericParams->getParams().front()
->getDeclaredInterfaceType()
->castTo<GenericTypeParamType>();
}
Type DeclContext::getDeclaredTypeInContext() const {
if (auto declaredType = getDeclaredInterfaceType())
return mapTypeIntoContext(declaredType);
return Type();
}
Type DeclContext::getDeclaredInterfaceType() const {
if (auto *ED = dyn_cast<ExtensionDecl>(this)) {
auto *NTD = ED->getExtendedNominal();
if (NTD == nullptr)
return ErrorType::get(ED->getASTContext());
return NTD->getDeclaredInterfaceType();
}
if (auto *NTD = dyn_cast<NominalTypeDecl>(this))
return NTD->getDeclaredInterfaceType();
return Type();
}
void DeclContext::forEachGenericContext(
llvm::function_ref<void (GenericParamList *)> fn) const {
auto dc = this;
do {
if (auto decl = dc->getAsDecl()) {
// Extensions do not capture outer generic parameters.
if (auto *ext = dyn_cast<ExtensionDecl>(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);
}
} while ((dc = dc->getParent()));
}
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<AbstractFunctionDecl>(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;
}
bool DeclContext::isTypeContext() const {
if (auto decl = getAsDecl())
return isa<NominalTypeDecl>(decl) || isa<ExtensionDecl>(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<ModuleDecl>(decl) ? nullptr : decl;
} while ((DC = DC->getParent()));
return nullptr;
}
DeclContext *DeclContext::getInnermostSkippedFunctionContext() {
auto dc = this;
do {
if (auto afd = dyn_cast<AbstractFunctionDecl>(dc))
if (afd->isBodySkipped())
return afd;
} while ((dc = dc->getParent()));
return nullptr;
}
DeclContext *DeclContext::getParentForLookup() const {
if (isa<ProtocolDecl>(this) || isa<ExtensionDecl>(this)) {
// If we are inside a protocol or an extension, skip directly
// to the module scope context, without looking at any (invalid)
// outer types.
return getModuleScopeContext();
}
if (isa<NominalTypeDecl>(this)) {
// If we are inside a nominal type that is inside a protocol,
// skip the protocol.
if (isa<ProtocolDecl>(getParent()))
return getModuleScopeContext();
}
return getParent();
}
ModuleDecl *DeclContext::getParentModule() const {
const DeclContext *DC = this;
while (!DC->isModuleContext())
DC = DC->getParent();
return const_cast<ModuleDecl *>(cast<ModuleDecl>(DC));
}
SourceFile *DeclContext::getParentSourceFile() const {
const DeclContext *DC = this;
while (!DC->isModuleScopeContext())
DC = DC->getParent();
return const_cast<SourceFile *>(dyn_cast<SourceFile>(DC));
}
DeclContext *DeclContext::getModuleScopeContext() const {
auto DC = const_cast<DeclContext*>(this);
while (true) {
if (DC->ParentAndKind.getInt() == ASTHierarchy::FileUnit)
return DC;
if (auto NextDC = DC->getParent()) {
DC = NextDC;
} else {
assert(isa<ModuleDecl>(DC->getAsDecl()));
return DC;
}
}
}
void DeclContext::getSeparatelyImportedOverlays(
ModuleDecl *declaring, SmallVectorImpl<ModuleDecl *> &overlays) const {
if (auto SF = getParentSourceFile())
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:
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<DeclContext *>(this) },
{FragileFunctionKind::None, false});
}
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<DefaultArgumentInitializer>(dc)) {
dc = dc->getParent();
auto *VD = cast<ValueDecl>(dc->getAsDecl());
assert(VD->hasParameterList());
if (VD->getDeclContext()->isLocalContext()) {
auto kind = VD->getDeclContext()->getFragileFunctionKind();
if (kind.kind != FragileFunctionKind::None)
return {FragileFunctionKind::DefaultArgument,
kind.allowUsableFromInline};
}
auto effectiveAccess =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
auto formalAccess =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/false);
if (effectiveAccess.isPublic()) {
return {FragileFunctionKind::DefaultArgument,
!formalAccess.isPublic()};
}
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};
}
// Stored property initializer contexts use minimal resilience expansion
// if the type is formally fixed layout.
if (isa<PatternBindingInitializer>(dc)) {
if (auto *NTD = dyn_cast<NominalTypeDecl>(dc->getParent())) {
auto nominalAccess =
NTD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
if (!nominalAccess.isPublic())
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};
if (NTD->isFormallyResilient())
return {FragileFunctionKind::None,
/*allowUsableFromInline=*/false};
return {FragileFunctionKind::PropertyInitializer, true};
}
}
if (auto *AFD = dyn_cast<AbstractFunctionDecl>(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,
/*allowUsableFromInline=*/false};
}
// If the function is public, @_transparent implies @inlinable.
if (AFD->isTransparent()) {
return {FragileFunctionKind::Transparent,
/*allowUsableFromInline=*/true};
}
if (AFD->getAttrs().hasAttribute<InlinableAttr>()) {
return {FragileFunctionKind::Inlinable,
/*allowUsableFromInline=*/true};
}
if (AFD->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
return {FragileFunctionKind::AlwaysEmitIntoClient,
/*allowUsableFromInline=*/true};
}
// If a property or subscript is @inlinable or @_alwaysEmitIntoClient,
// the accessors are @inlinable or @_alwaysEmitIntoClient also.
if (auto accessor = dyn_cast<AccessorDecl>(AFD)) {
auto *storage = accessor->getStorage();
if (storage->getAttrs().getAttribute<InlinableAttr>()) {
return {FragileFunctionKind::Inlinable,
/*allowUsableFromInline=*/true};
}
if (storage->getAttrs().hasAttribute<AlwaysEmitIntoClientAttr>()) {
return {FragileFunctionKind::AlwaysEmitIntoClient,
/*allowUsableFromInline=*/true};
}
}
}
}
return {FragileFunctionKind::None, false};
}
/// 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;
}
bool
DeclContext::isCascadingContextForLookup(bool functionsAreNonCascading) const {
// FIXME: This is explicitly checking for attributes in some cases because
// it can be called before access control is computed.
switch (getContextKind()) {
case DeclContextKind::AbstractClosureExpr:
break;
case DeclContextKind::SerializedLocal:
llvm_unreachable("should not perform lookups in deserialized contexts");
case DeclContextKind::Initializer:
// Default arguments still require a type.
if (isa<DefaultArgumentInitializer>(this))
return false;
break;
case DeclContextKind::TopLevelCodeDecl:
// FIXME: Pattern initializers at top-level scope end up here.
return true;
case DeclContextKind::AbstractFunctionDecl:
if (functionsAreNonCascading)
return false;
break;
case DeclContextKind::SubscriptDecl:
break;
case DeclContextKind::EnumElementDecl:
break;
case DeclContextKind::Module:
case DeclContextKind::FileUnit:
return true;
case DeclContextKind::GenericTypeDecl:
break;
case DeclContextKind::ExtensionDecl:
return true;
}
return getParent()->isCascadingContextForLookup(true);
}
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<ExtensionDecl>(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<ProtocolDecl>(this))
return PD->getAttrs().hasAttribute<ObjCAttr>();
return false;
}
bool DeclContext::canBeParentOfExtension() const {
return isa<SourceFile>(this);
}
bool DeclContext::walkContext(ASTWalker &Walker) {
switch (getContextKind()) {
case DeclContextKind::Module:
return cast<ModuleDecl>(this)->walk(Walker);
case DeclContextKind::FileUnit:
return cast<FileUnit>(this)->walk(Walker);
case DeclContextKind::AbstractClosureExpr:
return cast<AbstractClosureExpr>(this)->walk(Walker);
case DeclContextKind::GenericTypeDecl:
return cast<GenericTypeDecl>(this)->walk(Walker);
case DeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this)->walk(Walker);
case DeclContextKind::TopLevelCodeDecl:
return cast<TopLevelCodeDecl>(this)->walk(Walker);
case DeclContextKind::AbstractFunctionDecl:
return cast<AbstractFunctionDecl>(this)->walk(Walker);
case DeclContextKind::SubscriptDecl:
return cast<SubscriptDecl>(this)->walk(Walker);
case DeclContextKind::EnumElementDecl:
return cast<EnumElementDecl>(this)->walk(Walker);
case DeclContextKind::SerializedLocal:
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()) {
llvm::errs() << "(null)\n";
return;
}
if (auto *file = dyn_cast<SourceFile>(getDeclContext())) {
llvm::errs() << "file '" << file->getFilename() << "'\n";
return;
}
if (auto *decl = getDeclContext()->getAsDecl()) {
llvm::errs() << Decl::getKindName(decl->getKind()) << " ";
if (auto *ext = dyn_cast<ExtensionDecl>(decl))
llvm::errs() << ext->getExtendedNominal()->getName();
else if (auto *named = dyn_cast<ValueDecl>(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 <typename DCType>
static unsigned getLineNumber(DCType *DC) {
SourceLoc loc = DC->getLoc();
if (loc.isInvalid())
return 0;
const ASTContext &ctx = static_cast<const DeclContext *>(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::Module: Kind = "Module"; break;
case DeclContextKind::FileUnit: Kind = "FileUnit"; break;
case DeclContextKind::SerializedLocal: Kind = "Serialized Local"; break;
case DeclContextKind::AbstractClosureExpr:
Kind = "AbstractClosureExpr";
break;
case DeclContextKind::GenericTypeDecl:
switch (cast<GenericTypeDecl>(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::Initializer: Kind = "Initializer"; break;
case DeclContextKind::AbstractFunctionDecl:
Kind = "AbstractFunctionDecl";
break;
case DeclContextKind::SubscriptDecl: Kind = "SubscriptDecl"; break;
case DeclContextKind::EnumElementDecl: Kind = "EnumElementDecl"; break;
}
OS.indent(Depth*2 + indent) << (void*)this << " " << Kind;
switch (getContextKind()) {
case DeclContextKind::Module:
OS << " name=" << cast<ModuleDecl>(this)->getName();
break;
case DeclContextKind::FileUnit:
switch (cast<FileUnit>(this)->getKind()) {
case FileUnitKind::Builtin:
OS << " Builtin";
break;
case FileUnitKind::Source:
OS << " file=\"" << cast<SourceFile>(this)->getFilename() << "\"";
break;
case FileUnitKind::Synthesized:
OS << " synthesized file";
break;
case FileUnitKind::SerializedAST:
case FileUnitKind::ClangModule:
case FileUnitKind::DWARFModule:
OS << " file=\"" << cast<LoadedFile>(this)->getFilename() << "\"";
break;
}
break;
case DeclContextKind::AbstractClosureExpr:
OS << " line=" << getLineNumber(cast<AbstractClosureExpr>(this));
OS << " : " << cast<AbstractClosureExpr>(this)->getType();
break;
case DeclContextKind::GenericTypeDecl:
OS << " name=" << cast<GenericTypeDecl>(this)->getName();
break;
case DeclContextKind::ExtensionDecl:
OS << " line=" << getLineNumber(cast<ExtensionDecl>(this));
OS << " base=" << cast<ExtensionDecl>(this)->getExtendedType();
break;
case DeclContextKind::TopLevelCodeDecl:
OS << " line=" << getLineNumber(cast<TopLevelCodeDecl>(this));
break;
case DeclContextKind::AbstractFunctionDecl: {
auto *AFD = cast<AbstractFunctionDecl>(this);
OS << " name=" << AFD->getName();
if (AFD->hasInterfaceType())
OS << " : " << AFD->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::SubscriptDecl: {
auto *SD = cast<SubscriptDecl>(this);
OS << " name=" << SD->getBaseName();
if (SD->hasInterfaceType())
OS << " : " << SD->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::EnumElementDecl: {
auto *EED = cast<EnumElementDecl>(this);
OS << " name=" << EED->getBaseName();
if (EED->hasInterfaceType())
OS << " : " << EED->getInterfaceType();
else
OS << " : (no type set)";
break;
}
case DeclContextKind::Initializer:
switch (cast<Initializer>(this)->getInitializerKind()) {
case InitializerKind::PatternBinding: {
auto init = cast<PatternBindingInitializer>(this);
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case InitializerKind::DefaultArgument: {
auto init = cast<DefaultArgumentInitializer>(this);
OS << " DefaultArgument index=" << init->getIndex();
break;
}
}
break;
case DeclContextKind::SerializedLocal: {
auto local = cast<SerializedLocalDeclContext>(this);
switch (local->getLocalDeclContextKind()) {
case LocalDeclContextKind::AbstractClosure: {
auto serializedClosure = cast<SerializedAbstractClosureExpr>(local);
OS << " closure : " << serializedClosure->getType();
break;
}
case LocalDeclContextKind::DefaultArgumentInitializer: {
auto init = cast<SerializedDefaultArgumentInitializer>(local);
OS << "DefaultArgument index=" << init->getIndex();
break;
}
case LocalDeclContextKind::PatternBindingInitializer: {
auto init = cast<SerializedPatternBindingInitializer>(local);
OS << " PatternBinding 0x" << (void*) init->getBinding()
<< " #" << init->getBindingIndex();
break;
}
case LocalDeclContextKind::TopLevelCodeDecl:
OS << " TopLevelCode";
break;
}
}
}
if (!onlyAPartialLine)
OS << "\n";
return Depth + 1;
}
const Decl *
IterableDeclContext::getDecl() const {
switch (getIterableContextKind()) {
case IterableDeclContextKind::NominalTypeDecl:
return cast<NominalTypeDecl>(this);
break;
case IterableDeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this);
break;
}
llvm_unreachable("Unhandled IterableDeclContextKind in switch.");
}
GenericContext *IterableDeclContext::getAsGenericContext() {
switch (getIterableContextKind()) {
case IterableDeclContextKind::NominalTypeDecl:
return cast<NominalTypeDecl>(this);
case IterableDeclContextKind::ExtensionDecl:
return cast<ExtensionDecl>(this);
}
llvm_unreachable("Unhandled IterableDeclContextKind in switch.");
}
ASTContext &IterableDeclContext::getASTContext() const {
return getDecl()->getASTContext();
}
DeclRange IterableDeclContext::getCurrentMembersWithoutLoading() const {
return DeclRange(FirstDeclAndLazyMembers.getPointer(), nullptr);
}
DeclRange IterableDeclContext::getMembers() const {
loadAllMembers();
return getCurrentMembersWithoutLoading();
}
/// Add a member to this context.
void IterableDeclContext::addMember(Decl *member, Decl *Hint) {
// Add the member to the list of declarations without notification.
addMemberSilently(member, Hint);
++MemberCount;
// 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<NominalTypeDecl>(this);
nominal->addedMember(member);
assert(member->getDeclContext() == nominal &&
"Added member to the wrong context");
break;
}
case IterableDeclContextKind::ExtensionDecl: {
auto ext = cast<ExtensionDecl>(this);
ext->addedMember(member);
assert(member->getDeclContext() == ext &&
"Added member to the wrong context");
break;
}
}
}
void IterableDeclContext::addMemberSilently(Decl *member, Decl *hint) const {
assert(!isa<AccessorDecl>(member) && "Accessors should not be added here");
assert(!member->NextDecl && "Already added to a container");
// If there is a hint decl that specifies where to add this, just
// link into the chain immediately following it.
if (hint) {
member->NextDecl = hint->NextDecl;
hint->NextDecl = member;
// If the hint was the last in the parent context's chain, update it.
if (LastDeclAndKind.getPointer() == hint)
LastDeclAndKind.setPointer(member);
return;
}
if (auto last = LastDeclAndKind.getPointer()) {
last->NextDecl = member;
assert(last != member && "Simple cycle in decl list");
} else {
FirstDeclAndLazyMembers.setPointer(member);
}
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<IterableDeclContext *>(this)->AddedParsedMembers = 1;
return false;
}
return true;
}
unsigned IterableDeclContext::getMemberCount() const {
if (hasUnparsedMembers())
loadAllMembers();
return MemberCount;
}
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<IterableDeclContext *>(this);
auto members =
evaluateOrDefault(ctx.evaluator, ParseMembersRequest{mutableThis},
FingerprintAndMembers())
.members;
// 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.
FirstDeclAndLazyMembers.setInt(false);
const Decl *container = getDecl();
auto contextInfo = ctx.getOrCreateLazyIterableContextData(this,
/*lazyLoader=*/nullptr);
contextInfo->loader->loadAllMembers(const_cast<Decl *>(container),
contextInfo->memberData);
--NumUnloadedLazyIterableDeclContexts;
// FIXME: (transitional) decrement the redundant "always-on" counter.
if (auto s = ctx.Stats)
--s->getFrontendCounters().NumUnloadedLazyIterableDeclContexts;
}
bool IterableDeclContext::wasDeserialized() const {
const DeclContext *DC = getAsGenericContext();
if (auto F = dyn_cast<FileUnit>(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<IterableDeclContext *>( \
static_cast<const IterableDeclContext*>(cast<ID##Decl>(D)));
#include "swift/AST/DeclNodes.def"
}
}
Optional<std::string> IterableDeclContext::getBodyFingerprint() const {
// Only makes sense for contexts in a source file
if (!getAsGenericContext()->getParentSourceFile())
return None;
auto mutableThis = const_cast<IterableDeclContext *>(this);
return evaluateOrDefault(getASTContext().evaluator,
ParseMembersRequest{mutableThis},
FingerprintAndMembers())
.fingerprint;
}
bool IterableDeclContext::areTokensHashedForThisBodyInsteadOfInterfaceHash()
const {
// Do not keep separate hashes for extension bodies because the dependencies
// can miss the addition of a member in an extension because there is nothing
// corresponding to the fingerprinted nominal dependency node.
if (isa<ExtensionDecl>(this))
return false;
return getASTContext().LangOpts.EnableTypeFingerprints;
}
/// 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->getParentSourceFile() == useSF)
return NTD;
// Otherwise use the last extension declaration in the same file.
const DeclContext *lastExtension = nullptr;
for (ExtensionDecl *ED : NTD->getExtensions())
if (ED->getParentSourceFile() == useSF)
lastExtension = ED;
// If there's no last extension, return the supplied context.
return lastExtension ? lastExtension : DC;
}
AccessScope::AccessScope(const DeclContext *DC, bool isPrivate, bool isSPI)
: Value(DC, isPrivate || isSPI) {
if (isPrivate) {
DC = getPrivateDeclContext(DC, DC->getParentSourceFile());
Value.setPointer(DC);
}
if (!DC || isa<ModuleDecl>(DC))
assert(!isPrivate && "public or internal scope can't be private");
if (DC)
assert(!isSPI && "only public scopes can be SPI");
}
bool AccessScope::isFileScope() const {
auto DC = getDeclContext();
return DC && isa<FileUnit>(DC);
}
bool AccessScope::isInternal() const {
auto DC = getDeclContext();
return DC && isa<ModuleDecl>(DC);
}
AccessLevel AccessScope::accessLevelForDiagnostics() const {
if (isPublic())
return AccessLevel::Public;
if (isa<ModuleDecl>(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;
// Do not allow access if the sourceDC is in a different file
auto useSF = useDC->getParentSourceFile();
if (useSF != sourceDC->getParentSourceFile())
return false;
// Do not allow access if the sourceDC does not represent a type.
auto sourceNTD = sourceDC->getSelfNominalTypeDecl();
if (!sourceNTD)
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<ModuleDecl>(this))
return const_cast<ModuleDecl *>(module);
return nullptr;
}
DeclContextKind DeclContext::getContextKind() const {
switch (ParentAndKind.getInt()) {
case ASTHierarchy::Expr:
return DeclContextKind::AbstractClosureExpr;
case ASTHierarchy::Initializer:
return DeclContextKind::Initializer;
case ASTHierarchy::SerializedLocal:
return DeclContextKind::SerializedLocal;
case ASTHierarchy::FileUnit:
return DeclContextKind::FileUnit;
case ASTHierarchy::Decl: {
auto decl = reinterpret_cast<const Decl*>(this + 1);
if (isa<AbstractFunctionDecl>(decl))
return DeclContextKind::AbstractFunctionDecl;
if (isa<GenericTypeDecl>(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;
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<ExtensionDecl>(this);
return ED->getGenericSignature()->requiresClass(ED->getSelfInterfaceType());
}
return false;
}
SourceLoc swift::extractNearestSourceLoc(const DeclContext *dc) {
switch (dc->getContextKind()) {
case DeclContextKind::Module:
return SourceLoc();
case DeclContextKind::AbstractFunctionDecl:
case DeclContextKind::EnumElementDecl:
case DeclContextKind::ExtensionDecl:
case DeclContextKind::GenericTypeDecl:
case DeclContextKind::SubscriptDecl:
case DeclContextKind::TopLevelCodeDecl:
return extractNearestSourceLoc(dc->getAsDecl());
case DeclContextKind::AbstractClosureExpr: {
SourceLoc loc = cast<AbstractClosureExpr>(dc)->getLoc();
if (loc.isValid())
return loc;
return extractNearestSourceLoc(dc->getParent());
}
case DeclContextKind::FileUnit:
return SourceLoc();
case DeclContextKind::Initializer:
case DeclContextKind::SerializedLocal:
return extractNearestSourceLoc(dc->getParent());
}
llvm_unreachable("Unhandled DeclCopntextKindin switch");
}
#define DECL(Id, Parent) \
static_assert(!std::is_base_of<DeclContext, Id##Decl>::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<DeclContext, Id##Decl>::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<DeclContext, Id##Decl>::value, \
"CONTEXT_VALUE_DECL nodes must inherit from DeclContext");
#include "swift/AST/DeclNodes.def"
#define EXPR(Id, Parent) \
static_assert(!std::is_base_of<DeclContext, Id##Expr>::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<DeclContext, Id##Expr>::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<Decl*>(0x1000 + sizeof(DeclContext));
#define DECL(Id, Parent)
#define CONTEXT_DECL(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Decl*>(decl));
#define CONTEXT_VALUE_DECL(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Decl*>(decl));
#include "swift/AST/DeclNodes.def"
auto expr = reinterpret_cast<Expr*>(0x1000 + sizeof(DeclContext));
#define EXPR(Id, Parent)
#define CONTEXT_EXPR(Id, Parent) \
assert(reinterpret_cast<DeclContext*>(0x1000) == \
static_cast<Id##Expr*>(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());
}