| //===--- 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; |
| } |