blob: 6a0ed26012aded476e294a341b6725b7252b45fa [file] [log] [blame]
//===--- ASTScopeLookup.cpp - Swift Object-Oriented AST Scope -------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// This file implements the lookup functionality of the ASTScopeImpl ontology.
///
//===----------------------------------------------------------------------===//
#include "swift/AST/ASTScope.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTWalker.h"
#include "swift/AST/Decl.h"
#include "swift/AST/Expr.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/Module.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/SourceFile.h"
#include "swift/AST/Stmt.h"
#include "swift/AST/TypeRepr.h"
#include "swift/Basic/STLExtras.h"
#include "llvm/Support/Compiler.h"
#include <algorithm>
using namespace swift;
using namespace namelookup;
using namespace ast_scope;
llvm::SmallVector<const ASTScopeImpl *, 0> ASTScopeImpl::unqualifiedLookup(
SourceFile *sourceFile, const DeclName name, const SourceLoc loc,
const DeclContext *const startingContext, DeclConsumer consumer) {
SmallVector<const ASTScopeImpl *, 0> history;
const auto *start =
findStartingScopeForLookup(sourceFile, name, loc, startingContext);
if (start)
start->lookup(history, nullptr, nullptr, consumer);
return history;
}
const ASTScopeImpl *ASTScopeImpl::findStartingScopeForLookup(
SourceFile *sourceFile, const DeclName name, const SourceLoc loc,
const DeclContext *const startingContext) {
// At present, use legacy code in unqualifiedLookup.cpp to handle module-level
// lookups
// TODO: implement module scope someday
if (startingContext->getContextKind() == DeclContextKind::Module)
return nullptr;
auto *const fileScope = sourceFile->getScope().impl;
// Parser may have added decls to source file, since previous lookup
if (name.isOperator())
return fileScope; // operators always at file scope
const auto innermost = fileScope->findInnermostEnclosingScope(loc, nullptr);
ASTScopeAssert(innermost->getWasExpanded(),
"If looking in a scope, it must have been expanded.");
// The legacy lookup code gets passed both a SourceLoc and a starting context.
// However, our ultimate intent is for clients to not have to pass in a
// DeclContext at all, since the SourceLoc should be enough. While we are
// debugging the new ASTScope lookup code, we can catch bugs by comparing the
// DeclContext of the ASTScope found from the desired SourceLoc to the
// DeclContext passed in by the client.
const auto *startingScope = innermost;
for (; startingScope &&
!startingScope->doesContextMatchStartingContext(startingContext);
startingScope = startingScope->getParent().getPtrOrNull()) {
}
// Someday, just use the assertion below. For now, print out lots of info for
// debugging.
if (!startingScope) {
llvm::errs() << "ASTScopeImpl: resorting to startingScope hack, file: "
<< sourceFile->getFilename() << "\n";
llvm::errs() << "'";
name.print(llvm::errs());
llvm::errs() << "' ";
llvm::errs() << "loc: ";
loc.dump(sourceFile->getASTContext().SourceMgr);
llvm::errs() << "\nstarting context:\n ";
startingContext->dumpContext();
// llvm::errs() << "\ninnermost: ";
// innermost->dump();
// llvm::errs() << "in: \n";
// fileScope->dump();
llvm::errs() << "\n\n";
// Might distort things
// if (fileScope->crossCheckWithAST())
// llvm::errs() << "Tree creation missed some DeclContexts.\n";
}
ASTScopeAssert(startingScope, "ASTScopeImpl: could not find startingScope");
return startingScope;
}
const ASTScopeImpl *
ASTScopeImpl::findInnermostEnclosingScope(SourceLoc loc,
NullablePtr<raw_ostream> os) {
return findInnermostEnclosingScopeImpl(loc, os, getSourceManager(),
getScopeCreator());
}
const ASTScopeImpl *ASTScopeImpl::findInnermostEnclosingScopeImpl(
SourceLoc loc, NullablePtr<raw_ostream> os, SourceManager &sourceMgr,
ScopeCreator &scopeCreator) {
expandAndBeCurrentDetectingRecursion(scopeCreator);
auto child = findChildContaining(loc, sourceMgr);
if (!child)
return this;
return child.get()->findInnermostEnclosingScopeImpl(loc, os, sourceMgr,
scopeCreator);
}
bool ASTScopeImpl::checkSourceRangeOfThisASTNode() const {
const auto r = getSourceRangeOfThisASTNode();
(void)r;
ASTScopeAssert(!getSourceManager().isBeforeInBuffer(r.End, r.Start),
"Range is backwards.");
return true;
}
NullablePtr<ASTScopeImpl>
ASTScopeImpl::findChildContaining(SourceLoc loc,
SourceManager &sourceMgr) const {
// Use binary search to find the child that contains this location.
struct CompareLocs {
SourceManager &sourceMgr;
bool operator()(const ASTScopeImpl *scope, SourceLoc loc) {
ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(scope->getSourceRangeOfScope().End,
loc);
}
bool operator()(SourceLoc loc, const ASTScopeImpl *scope) {
ASTScopeAssert(scope->checkSourceRangeOfThisASTNode(), "Bad range.");
return sourceMgr.isBeforeInBuffer(loc,
scope->getSourceRangeOfScope().End);
}
};
auto *const *child = std::lower_bound(
getChildren().begin(), getChildren().end(), loc, CompareLocs{sourceMgr});
if (child != getChildren().end() &&
sourceMgr.rangeContainsTokenLoc((*child)->getSourceRangeOfScope(), loc))
return *child;
return nullptr;
}
#pragma mark doesContextMatchStartingContext
// Match existing UnqualifiedLookupBehavior
bool ASTScopeImpl::doesContextMatchStartingContext(
const DeclContext *context) const {
// Why are we not checking the loc for this--because already did binary search
// on loc to find the start First, try MY DeclContext
if (auto myDCForL = getDeclContext())
return myDCForL == context;
// If I don't have one, ask my parent.
// (Choose innermost scope with matching loc & context.)
if (auto p = getParent())
return p.get()->doesContextMatchStartingContext(context);
// Topmost scope always has a context, the SourceFile.
ASTScope_unreachable("topmost scope always has a context, the SourceFile");
}
// For a SubscriptDecl with generic parameters, the call tries to do lookups
// with startingContext equal to either the get or set subscript
// AbstractFunctionDecls. Since the generic parameters are in the
// SubScriptDeclScope, and not the AbstractFunctionDecl scopes (after all how
// could one parameter be in two scopes?), GenericParamScoped intercepts the
// match query here and tests against the accessor DeclContexts.
bool GenericParamScope::doesContextMatchStartingContext(
const DeclContext *context) const {
if (auto *asd = dyn_cast<AbstractStorageDecl>(holder)) {
for (auto accessor : asd->getAllAccessors()) {
if (up_cast<DeclContext>(accessor) == context)
return true;
}
}
return false;
}
// SWIFT_ENABLE_TENSORFLOW
bool DifferentiableAttributeScope::doesContextMatchStartingContext(
const DeclContext *context) const {
// Need special logic to handle case where `attributedDeclaration` is an
// `AbstractStorageDecl` (`SubscriptDecl` or `VarDecl`). The initial starting
// context in `ASTScopeImpl::findStartingScopeForLookup` will be an accessor
// of the `attributedDeclaration`.
if (auto *asd = dyn_cast<AbstractStorageDecl>(attributedDeclaration))
for (auto accessor : asd->getAllAccessors())
if (up_cast<DeclContext>(accessor) == context)
return true;
return false;
}
// SWIFT_ENABLE_TENSORFLOW END
#pragma mark lookup methods that run once per scope
void ASTScopeImpl::lookup(SmallVectorImpl<const ASTScopeImpl *> &history,
const NullablePtr<const ASTScopeImpl> limit,
NullablePtr<const GenericParamList> lastListSearched,
DeclConsumer consumer) const {
history.push_back(this);
#ifndef NDEBUG
consumer.startingNextLookupStep();
#endif
// Certain illegal nestings, e.g. protocol nestled inside a struct,
// require that lookup stop at the outer scope.
if (this == limit.getPtrOrNull()) {
#ifndef NDEBUG
consumer.finishingLookup("limit return");
#endif
return;
}
// Look for generics before members in violation of lexical ordering because
// you can say "self.name" to get a name shadowed by a generic but you
// can't do the opposite to get a generic shadowed by a name.
const auto doneAndListSearched =
lookInMyGenericParameters(lastListSearched, consumer);
if (doneAndListSearched.first)
return;
if (lookupLocalsOrMembers(history, consumer))
return;
const auto *const lookupParent = getLookupParent().getPtrOrNull();
if (!lookupParent) {
#ifndef NDEBUG
consumer.finishingLookup("Finished lookup; no parent");
#endif
return;
}
// If there is no limit and this scope induces one, pass that on.
const NullablePtr<const ASTScopeImpl> limitForParent =
limit ? limit : getLookupLimit();
return lookupParent->lookup(history, limitForParent, lastListSearched,
consumer);
}
#pragma mark genericParams()
NullablePtr<const GenericParamList> ASTScopeImpl::genericParams() const {
return nullptr;
}
NullablePtr<const GenericParamList>
AbstractFunctionDeclScope::genericParams() const {
return decl->getGenericParams();
}
NullablePtr<const GenericParamList> SubscriptDeclScope::genericParams() const {
return decl->getGenericParams();
}
NullablePtr<const GenericParamList> GenericTypeScope::genericParams() const {
// For Decls:
// WAIT, WHAT?! Isn't this covered by the GenericParamScope
// lookupLocalsOrMembers? No, that's for use of generics in the body. This is
// for generic restrictions.
// For Bodies:
// Sigh... These must be here so that from body, we search generics before
// members. But they also must be on the Decl scope for lookups starting from
// generic parameters, where clauses, etc.
return getGenericContext()->getGenericParams();
}
NullablePtr<const GenericParamList> ExtensionScope::genericParams() const {
return decl->getGenericParams();
}
#pragma mark lookInMyGenericParameters
std::pair<bool, NullablePtr<const GenericParamList>>
ASTScopeImpl::lookInMyGenericParameters(
NullablePtr<const GenericParamList> formerListSearched,
ASTScopeImpl::DeclConsumer consumer) const {
auto listToSearch = genericParams();
if (listToSearch == formerListSearched)
return std::make_pair(false, formerListSearched);
// For extensions of nested types, must check outer parameters
for (auto *params = listToSearch.getPtrOrNull(); params;
params = params->getOuterParameters()) {
if (lookInGenericParametersOf(params, consumer))
return std::make_pair(true, listToSearch);
}
return std::make_pair(false, listToSearch);
}
bool ASTScopeImpl::lookInGenericParametersOf(
const NullablePtr<const GenericParamList> paramList,
ASTScopeImpl::DeclConsumer consumer) {
if (!paramList)
return false;
SmallVector<ValueDecl *, 32> bindings;
for (auto *param : paramList.get()->getParams())
bindings.push_back(param);
if (consumer.consume(bindings, DeclVisibilityKind::GenericParameter))
return true;
return false;
}
#pragma mark looking in locals or members - members
bool ASTScopeImpl::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer) const {
return false; // many kinds of scopes have none
}
bool GenericTypeOrExtensionScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history,
ASTScopeImpl::DeclConsumer consumer) const {
// isCascadingUseArg must have already been resolved, for a real lookup
// but may be \c None for dumping.
return portion->lookupMembersOf(this, history, consumer);
}
bool Portion::lookupMembersOf(const GenericTypeOrExtensionScope *,
ArrayRef<const ASTScopeImpl *>,
ASTScopeImpl::DeclConsumer) const {
return false;
}
bool GenericTypeOrExtensionWhereOrBodyPortion::lookupMembersOf(
const GenericTypeOrExtensionScope *scope,
ArrayRef<const ASTScopeImpl *> history,
ASTScopeImpl::DeclConsumer consumer) const {
auto nt = scope->getCorrespondingNominalTypeDecl().getPtrOrNull();
if (!nt)
return false;
auto selfDC = computeSelfDC(history);
return consumer.lookInMembers(selfDC, scope->getDeclContext().get(), nt,
[&](Optional<bool> initialIsCascadingUse) {
return ASTScopeImpl::computeIsCascadingUse(
history, initialIsCascadingUse)
.getValueOr(true);
});
}
#pragma mark looking in locals or members - locals
bool GenericParamScope::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const {
auto *param = paramList->getParams()[index];
return consumer.consume({param}, DeclVisibilityKind::GenericParameter);
}
bool PatternEntryDeclScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
if (vis != DeclVisibilityKind::LocalVariable)
return false; // look in self type will find this later
return lookupLocalBindingsInPattern(getPattern(), vis, consumer);
}
bool ForEachPatternScope::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const {
return lookupLocalBindingsInPattern(
stmt->getPattern(), DeclVisibilityKind::LocalVariable, consumer);
}
bool CatchStmtScope::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const {
return lookupLocalBindingsInPattern(
stmt->getErrorPattern(), DeclVisibilityKind::LocalVariable, consumer);
}
bool CaseStmtScope::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const {
for (auto &item : stmt->getMutableCaseLabelItems())
if (lookupLocalBindingsInPattern(
item.getPattern(), DeclVisibilityKind::LocalVariable, consumer))
return true;
return false;
}
bool AbstractFunctionBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
if (auto *paramList = decl->getParameters()) {
for (auto *paramDecl : *paramList)
if (consumer.consume({paramDecl}, DeclVisibilityKind::FunctionParameter))
return true;
}
return false;
}
bool MethodBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const {
ASTScopeAssert(isAMethod(decl), "Asking for members of a non-method.");
if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true;
return consumer.consume({decl->getImplicitSelfDecl()},
DeclVisibilityKind::FunctionParameter);
}
bool PureFunctionBodyScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *> history, DeclConsumer consumer) const {
ASTScopeAssert(
!isAMethod(decl),
"Should have called lookupLocalsOrMembers instead of this function.");
if (AbstractFunctionBodyScope::lookupLocalsOrMembers(history, consumer))
return true;
// Consider \c var t: T { (did/will/)get/set { ... t }}
// Lookup needs to find t, but if the var is inside of a type the baseDC needs
// to be set. It all works fine, except: if the var is not inside of a type,
// then t needs to be found as a local binding:
if (auto *accessor = dyn_cast<AccessorDecl>(decl)) {
if (auto *storage = accessor->getStorage())
if (consumer.consume({storage}, DeclVisibilityKind::LocalVariable))
return true;
}
return false;
}
bool SpecializeAttributeScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
if (auto *params = whatWasSpecialized->getGenericParams())
for (auto *param : params->getParams())
if (consumer.consume({param}, DeclVisibilityKind::GenericParameter))
return true;
return false;
}
// SWIFT_ENABLE_TENSORFLOW
bool DifferentiableAttributeScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
auto visitAbstractFunctionDecl = [&](AbstractFunctionDecl *afd) {
if (auto *params = afd->getGenericParams())
for (auto *param : params->getParams())
if (consumer.consume({param}, DeclVisibilityKind::GenericParameter))
return true;
return false;
};
if (auto *afd = dyn_cast<AbstractFunctionDecl>(attributedDeclaration)) {
return visitAbstractFunctionDecl(afd);
} else if (auto *asd = dyn_cast<AbstractStorageDecl>(attributedDeclaration)) {
for (auto *accessor : asd->getAllAccessors())
if (visitAbstractFunctionDecl(accessor))
return true;
}
return false;
}
// SWIFT_ENABLE_TENSORFLOW END
bool BraceStmtScope::lookupLocalsOrMembers(ArrayRef<const ASTScopeImpl *>,
DeclConsumer consumer) const {
// All types and functions are visible anywhere within a brace statement
// scope. When ordering matters (i.e. var decl) we will have split the brace
// statement into nested scopes.
//
// Don't stop at the first one, there may be local funcs with same base name
// and want them all.
SmallVector<ValueDecl *, 32> localBindings;
for (auto braceElement : stmt->getElements()) {
if (auto localBinding = braceElement.dyn_cast<Decl *>()) {
if (auto *vd = dyn_cast<ValueDecl>(localBinding))
localBindings.push_back(vd);
}
}
return consumer.consume(localBindings, DeclVisibilityKind::LocalVariable);
}
bool PatternEntryInitializerScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
// 'self' is available within the pattern initializer of a 'lazy' variable.
auto *initContext = cast_or_null<PatternBindingInitializer>(
decl->getPatternList()[0].getInitContext());
if (initContext) {
if (auto *selfParam = initContext->getImplicitSelfDecl()) {
return consumer.consume({selfParam},
DeclVisibilityKind::FunctionParameter);
}
}
return false;
}
bool ClosureParametersScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
if (auto *cl = captureList.getPtrOrNull()) {
CaptureListExpr *mutableCL =
const_cast<CaptureListExpr *>(captureList.get());
for (auto &e : mutableCL->getCaptureList()) {
if (consumer.consume(
{e.Var},
DeclVisibilityKind::LocalVariable)) // or FunctionParameter??
return true;
}
}
for (auto param : *closureExpr->getParameters())
if (consumer.consume({param}, DeclVisibilityKind::FunctionParameter))
return true;
return false;
}
bool ConditionalClausePatternUseScope::lookupLocalsOrMembers(
ArrayRef<const ASTScopeImpl *>, DeclConsumer consumer) const {
return lookupLocalBindingsInPattern(
pattern, DeclVisibilityKind::LocalVariable, consumer);
}
bool ASTScopeImpl::lookupLocalBindingsInPattern(Pattern *p,
DeclVisibilityKind vis,
DeclConsumer consumer) {
if (!p)
return false;
bool isDone = false;
p->forEachVariable([&](VarDecl *var) {
if (!isDone)
isDone = consumer.consume({var}, vis);
});
return isDone;
}
#pragma mark computeSelfDC
NullablePtr<DeclContext>
GenericTypeOrExtensionWhereOrBodyPortion::computeSelfDC(
ArrayRef<const ASTScopeImpl *> history) {
ASTScopeAssert(history.size() != 0, "includes current scope");
size_t i = history.size() - 1; // skip last entry (this scope)
while (i != 0) {
Optional<NullablePtr<DeclContext>> maybeSelfDC =
history[--i]->computeSelfDCForParent();
if (maybeSelfDC)
return *maybeSelfDC;
}
return nullptr;
}
#pragma mark compute isCascadingUse
Optional<bool> ASTScopeImpl::computeIsCascadingUse(
ArrayRef<const ASTScopeImpl *> history,
const Optional<bool> initialIsCascadingUse) {
Optional<bool> isCascadingUse = initialIsCascadingUse;
for (const auto *scope : history)
isCascadingUse = scope->resolveIsCascadingUseForThisScope(isCascadingUse);
return isCascadingUse;
}
#pragma mark getLookupLimit
NullablePtr<const ASTScopeImpl> ASTScopeImpl::getLookupLimit() const {
return nullptr;
}
NullablePtr<const ASTScopeImpl>
GenericTypeOrExtensionScope::getLookupLimit() const {
return portion->getLookupLimitFor(this);
}
NullablePtr<const ASTScopeImpl>
Portion::getLookupLimitFor(const GenericTypeOrExtensionScope *) const {
return nullptr;
}
NullablePtr<const ASTScopeImpl>
GenericTypeOrExtensionWholePortion::getLookupLimitFor(
const GenericTypeOrExtensionScope *scope) const {
return scope->getLookupLimitForDecl();
}
NullablePtr<const ASTScopeImpl>
GenericTypeOrExtensionScope::getLookupLimitForDecl() const {
return nullptr;
}
NullablePtr<const ASTScopeImpl>
NominalTypeScope::getLookupLimitForDecl() const {
if (isa<ProtocolDecl>(decl)) {
// ProtocolDecl can only be legally nested in a SourceFile,
// so any other kind of Decl is illegal
return parentIfNotChildOfTopScope();
}
// AFAICT, a struct, decl, or enum can be nested inside anything
// but a ProtocolDecl.
return ancestorWithDeclSatisfying(
[&](const Decl *const d) { return isa<ProtocolDecl>(d); });
}
NullablePtr<const ASTScopeImpl> ExtensionScope::getLookupLimitForDecl() const {
// Extensions can only be legally nested in a SourceFile,
// so any other kind of Decl is illegal
return parentIfNotChildOfTopScope();
}
NullablePtr<const ASTScopeImpl> ASTScopeImpl::ancestorWithDeclSatisfying(
function_ref<bool(const Decl *)> predicate) const {
for (NullablePtr<const ASTScopeImpl> s = getParent(); s;
s = s.get()->getParent()) {
if (Decl *d = s.get()->getDeclIfAny().getPtrOrNull()) {
if (predicate(d))
return s;
}
}
return nullptr;
}
#pragma mark computeSelfDCForParent
// If the lookup depends on implicit self, selfDC is its context.
// (Names in extensions never depend on self.)
// Lookup can propagate it up from, say a method to the enclosing type body.
// By default, propagate the selfDC up to a NomExt decl, body,
// or where clause
Optional<NullablePtr<DeclContext>>
ASTScopeImpl::computeSelfDCForParent() const {
return None;
}
// Forget the "self" declaration:
Optional<NullablePtr<DeclContext>>
GenericTypeOrExtensionScope::computeSelfDCForParent() const {
return NullablePtr<DeclContext>();
}
Optional<NullablePtr<DeclContext>>
PatternEntryInitializerScope::computeSelfDCForParent() const {
// Pattern binding initializers are only interesting insofar as they
// affect lookup in an enclosing nominal type or extension thereof.
if (auto *ic = getPatternEntry().getInitContext()) {
if (auto *bindingInit = dyn_cast<PatternBindingInitializer>(ic)) {
// Lazy variable initializer contexts have a 'self' parameter for
// instance member lookup.
if (bindingInit->getImplicitSelfDecl()) {
return NullablePtr<DeclContext>(bindingInit);
}
}
}
return None;
}
Optional<NullablePtr<DeclContext>>
MethodBodyScope::computeSelfDCForParent() const {
return NullablePtr<DeclContext>(decl);
}
#pragma mark ifUnknownIsCascadingUseAccordingTo
static bool isCascadingUseAccordingTo(const DeclContext *const dc) {
return dc->isCascadingContextForLookup(false);
}
static bool ifUnknownIsCascadingUseAccordingTo(Optional<bool> isCascadingUse,
const DeclContext *const dc) {
return isCascadingUse.getValueOr(isCascadingUseAccordingTo(dc));
}
#pragma mark resolveIsCascadingUseForThisScope
Optional<bool> ASTScopeImpl::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
return isCascadingUse;
}
Optional<bool> GenericParamScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
if (auto *dc = getDeclContext().getPtrOrNull())
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, dc);
ASTScope_unreachable("generic what?");
}
Optional<bool> AbstractFunctionDeclScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
return decl->isCascadingContextForLookup(false) &&
isCascadingUse.getValueOr(true);
}
Optional<bool> AbstractFunctionBodyScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
return false;
}
Optional<bool> GenericTypeOrExtensionScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
// Could override for ExtensionScope and just return true
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse,
getDeclContext().get());
}
Optional<bool>
DefaultArgumentInitializerScope::resolveIsCascadingUseForThisScope(
Optional<bool>) const {
return false;
}
Optional<bool> ClosureParametersScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, closureExpr);
}
Optional<bool> ClosureBodyScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, closureExpr);
}
Optional<bool> PatternEntryInitializerScope::resolveIsCascadingUseForThisScope(
Optional<bool> isCascadingUse) const {
auto *const initContext = getPatternEntry().getInitContext();
auto *PBI = cast_or_null<PatternBindingInitializer>(initContext);
auto *isd = PBI ? PBI->getImplicitSelfDecl() : nullptr;
// 'self' is available within the pattern initializer of a 'lazy' variable.
if (isd)
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, PBI);
// initializing stored property of a type
auto *const patternDeclContext = decl->getDeclContext();
if (patternDeclContext->isTypeContext())
return isCascadingUseAccordingTo(PBI->getParent());
// initializing global or local
if (PBI)
return ifUnknownIsCascadingUseAccordingTo(isCascadingUse, PBI);
return isCascadingUse;
}