//===--- NameLookup.cpp - Swift Name Lookup Routines ----------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements interfaces for performing name lookup. // //===----------------------------------------------------------------------===// #include "swift/AST/NameLookup.h" #include "swift/AST/ASTContext.h" #include "swift/AST/ASTScope.h" #include "swift/AST/ASTVisitor.h" #include "swift/AST/ClangModuleLoader.h" #include "swift/AST/DebuggerClient.h" #include "swift/AST/ExistentialLayout.h" #include "swift/AST/LazyResolver.h" #include "swift/AST/Initializer.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" #include "swift/AST/ReferencedNameTracker.h" #include "swift/Basic/SourceManager.h" #include "swift/Basic/Statistic.h" #include "swift/Basic/STLExtras.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "namelookup" using namespace swift; using namespace swift::namelookup; void VisibleDeclConsumer::anchor() {} void VectorDeclConsumer::anchor() {} void NamedDeclConsumer::anchor() {} ValueDecl *LookupResultEntry::getBaseDecl() const { if (BaseDC == nullptr) return nullptr; if (auto *AFD = dyn_cast(BaseDC)) return AFD->getImplicitSelfDecl(); if (auto *PBI = dyn_cast(BaseDC)) { auto *selfDecl = PBI->getImplicitSelfDecl(); assert(selfDecl); return selfDecl; } auto *nominalDecl = BaseDC->getSelfNominalTypeDecl(); assert(nominalDecl); return nominalDecl; } void DebuggerClient::anchor() {} void AccessFilteringDeclConsumer::foundDecl(ValueDecl *D, DeclVisibilityKind reason) { if (D->isInvalid()) return; if (!D->isAccessibleFrom(DC)) return; ChainedConsumer.foundDecl(D, reason); } template static void forAllVisibleModules(const DeclContext *DC, const Fn &fn) { DeclContext *moduleScope = DC->getModuleScopeContext(); if (auto file = dyn_cast(moduleScope)) file->forAllVisibleModules(fn); else cast(moduleScope)->forAllVisibleModules(ModuleDecl::AccessPathTy(), fn); } bool swift::removeOverriddenDecls(SmallVectorImpl &decls) { if (decls.size() < 2) return false; llvm::SmallPtrSet overridden; for (auto decl : decls) { // Don't look at the overrides of operators in protocols. The global // lookup of operators means that we can find overriding operators that // aren't relevant to the types in hand, and will fail to type check. if (isa(decl->getDeclContext())) { if (auto func = dyn_cast(decl)) if (func->isOperator()) continue; } while (auto overrides = decl->getOverriddenDecl()) { overridden.insert(overrides); // Because initializers from Objective-C base classes have greater // visibility than initializers written in Swift classes, we can // have a "break" in the set of declarations we found, where // C.init overrides B.init overrides A.init, but only C.init and // A.init are in the chain. Make sure we still remove A.init from the // set in this case. if (decl->getFullName().getBaseName() == DeclBaseName::createConstructor()) { /// FIXME: Avoid the possibility of an infinite loop by fixing the root /// cause instead (incomplete circularity detection). assert(decl != overrides && "Circular class inheritance?"); decl = overrides; continue; } break; } } // If no methods were overridden, we're done. if (overridden.empty()) return false; // Erase any overridden declarations bool anyOverridden = false; decls.erase(std::remove_if(decls.begin(), decls.end(), [&](ValueDecl *decl) -> bool { if (overridden.count(decl) > 0) { anyOverridden = true; return true; } return false; }), decls.end()); return anyOverridden; } enum class ConstructorComparison { Worse, Same, Better, }; /// Determines whether \p ctor1 is a "better" initializer than \p ctor2. static ConstructorComparison compareConstructors(ConstructorDecl *ctor1, ConstructorDecl *ctor2, const swift::ASTContext &ctx) { bool available1 = !ctor1->getAttrs().isUnavailable(ctx); bool available2 = !ctor2->getAttrs().isUnavailable(ctx); // An unavailable initializer is always worse than an available initializer. if (available1 < available2) return ConstructorComparison::Worse; if (available1 > available2) return ConstructorComparison::Better; CtorInitializerKind kind1 = ctor1->getInitKind(); CtorInitializerKind kind2 = ctor2->getInitKind(); if (kind1 > kind2) return ConstructorComparison::Worse; if (kind1 < kind2) return ConstructorComparison::Better; return ConstructorComparison::Same; } /// Given a set of declarations whose names and signatures have matched, /// figure out which of these declarations have been shadowed by others. static void recordShadowedDeclsAfterSignatureMatch( ArrayRef decls, const ModuleDecl *curModule, llvm::SmallPtrSetImpl &shadowed) { assert(decls.size() > 1 && "Nothing collided"); // Compare each declaration to every other declaration. This is // unavoidably O(n^2) in the number of declarations, but because they // all have the same signature, we expect n to remain small. ASTContext &ctx = curModule->getASTContext(); for (unsigned firstIdx : indices(decls)) { auto firstDecl = decls[firstIdx]; auto firstModule = firstDecl->getModuleContext(); auto firstSig = firstDecl->getOverloadSignature(); for (unsigned secondIdx : range(firstIdx + 1, decls.size())) { // Determine whether one module takes precedence over another. auto secondDecl = decls[secondIdx]; auto secondModule = secondDecl->getModuleContext(); // Swift 4 compatibility hack: Don't shadow properties defined in // extensions of generic types with properties defined elsewhere. // This is due to the fact that in Swift 4, we only gave custom overload // types to properties in extensions of generic types, otherwise we // used the null type. if (!ctx.isSwiftVersionAtLeast(5)) { auto secondSig = secondDecl->getOverloadSignature(); if (firstSig.IsVariable && secondSig.IsVariable) if (firstSig.InExtensionOfGenericType != secondSig.InExtensionOfGenericType) continue; } // If one declaration is in a protocol or extension thereof and the // other is not, prefer the one that is not. if ((bool)firstDecl->getDeclContext()->getSelfProtocolDecl() != (bool)secondDecl->getDeclContext()->getSelfProtocolDecl()) { if (firstDecl->getDeclContext()->getSelfProtocolDecl()) { shadowed.insert(firstDecl); break; } else { shadowed.insert(secondDecl); continue; } } // If one declaration is available and the other is not, prefer the // available one. if (firstDecl->getAttrs().isUnavailable(ctx) != secondDecl->getAttrs().isUnavailable(ctx)) { if (firstDecl->getAttrs().isUnavailable(ctx)) { shadowed.insert(firstDecl); break; } else { shadowed.insert(secondDecl); continue; } } // Don't apply module-shadowing rules to members of protocol types. if (isa(firstDecl->getDeclContext()) || isa(secondDecl->getDeclContext())) continue; // Prefer declarations in the current module over those in another // module. // FIXME: This is a hack. We should query a (lazily-built, cached) // module graph to determine shadowing. if ((firstModule == curModule) != (secondModule == curModule)) { // If the first module is the current module, the second declaration // is shadowed by the first. if (firstModule == curModule) { shadowed.insert(secondDecl); continue; } // Otherwise, the first declaration is shadowed by the second. There is // no point in continuing to compare the first declaration to others. shadowed.insert(firstDecl); break; } // Prefer declarations in the any module over those in the standard // library module. if (auto swiftModule = ctx.getStdlibModule()) { if ((firstModule == swiftModule) != (secondModule == swiftModule)) { // If the second module is the standard library module, the second // declaration is shadowed by the first. if (secondModule == swiftModule) { shadowed.insert(secondDecl); continue; } // Otherwise, the first declaration is shadowed by the second. There is // no point in continuing to compare the first declaration to others. shadowed.insert(firstDecl); break; } } // The Foundation overlay introduced Data.withUnsafeBytes, which is // treated as being ambiguous with SwiftNIO's Data.withUnsafeBytes // extension. Apply a special-case name shadowing rule to use the // latter rather than the former, which be the consequence of a more // significant change to name shadowing in the future. if (auto owningStruct1 = firstDecl->getDeclContext()->getSelfStructDecl()) { if (auto owningStruct2 = secondDecl->getDeclContext()->getSelfStructDecl()) { if (owningStruct1 == owningStruct2 && owningStruct1->getName().is("Data") && isa(firstDecl) && isa(secondDecl) && firstDecl->getFullName() == secondDecl->getFullName() && firstDecl->getBaseName().userFacingName() == "withUnsafeBytes") { // If the second module is the Foundation module and the first // is the NIOFoundationCompat module, the second is shadowed by the // first. if (firstDecl->getModuleContext()->getName() .is("NIOFoundationCompat") && secondDecl->getModuleContext()->getName().is("Foundation")) { shadowed.insert(secondDecl); continue; } // If it's the other way around, the first declaration is shadowed // by the second. if (secondDecl->getModuleContext()->getName() .is("NIOFoundationCompat") && firstDecl->getModuleContext()->getName().is("Foundation")) { shadowed.insert(firstDecl); break; } } } } // Prefer declarations in an overlay to similar declarations in // the Clang module it customizes. if (firstDecl->hasClangNode() != secondDecl->hasClangNode()) { auto clangLoader = ctx.getClangModuleLoader(); if (!clangLoader) continue; if (clangLoader->isInOverlayModuleForImportedModule( firstDecl->getDeclContext(), secondDecl->getDeclContext())) { shadowed.insert(secondDecl); continue; } if (clangLoader->isInOverlayModuleForImportedModule( secondDecl->getDeclContext(), firstDecl->getDeclContext())) { shadowed.insert(firstDecl); break; } } } } } /// Look through the given set of declarations (that all have the same name), /// recording those that are shadowed by another declaration in the /// \c shadowed set. static void recordShadowDeclsAfterObjCInitMatch( ArrayRef ctors, llvm::SmallPtrSetImpl &shadowed) { assert(ctors.size() > 1 && "No collisions"); ASTContext &ctx = ctors.front()->getASTContext(); // Find the "best" constructor with this signature. ConstructorDecl *bestCtor = ctors[0]; for (auto ctor : ctors.slice(1)) { auto comparison = compareConstructors(ctor, bestCtor, ctx); if (comparison == ConstructorComparison::Better) bestCtor = ctor; } // Shadow any initializers that are worse. for (auto ctor : ctors) { auto comparison = compareConstructors(ctor, bestCtor, ctx); if (comparison == ConstructorComparison::Worse) shadowed.insert(ctor); } } /// Look through the given set of declarations (that all have the same name), /// recording those that are shadowed by another declaration in the /// \c shadowed set. static void recordShadowedDecls(ArrayRef decls, const ModuleDecl *curModule, llvm::SmallPtrSetImpl &shadowed) { if (decls.size() < 2) return; auto typeResolver = decls[0]->getASTContext().getLazyResolver(); // Categorize all of the declarations based on their overload signatures. llvm::SmallDenseMap> collisions; llvm::SmallVector collisionTypes; llvm::SmallDenseMap> objCInitializerCollisions; llvm::TinyPtrVector objCInitializerCollisionNominals; for (auto decl : decls) { // Specifically keep track of Objective-C initializers, which can come from // either init methods or factory methods. if (decl->hasClangNode()) { if (auto ctor = dyn_cast(decl)) { auto nominal = ctor->getDeclContext()->getSelfNominalTypeDecl(); auto &knownInits = objCInitializerCollisions[nominal]; if (knownInits.size() == 1) { objCInitializerCollisionNominals.push_back(nominal); } knownInits.push_back(ctor); } } CanType signature; if (!isa(decl)) { // We need an interface type here. if (typeResolver) typeResolver->resolveDeclSignature(decl); // If the decl is currently being validated, this is likely a recursive // reference and we'll want to skip ahead so as to avoid having its type // attempt to desugar itself. if (!decl->hasValidSignature()) continue; // FIXME: the canonical type makes a poor signature, because we don't // canonicalize away default arguments. signature = decl->getInterfaceType()->getCanonicalType(); // FIXME: The type of a variable or subscript doesn't include // enough context to distinguish entities from different // constrained extensions, so use the overload signature's // type. This is layering a partial fix upon a total hack. if (auto asd = dyn_cast(decl)) signature = asd->getOverloadSignatureType(); } else if (decl->getDeclContext()->isTypeContext()) { // Do not apply shadowing rules for member types. continue; } // Record this declaration based on its signature. auto &known = collisions[signature]; if (known.size() == 1) { collisionTypes.push_back(signature); } known.push_back(decl); } // Check whether we have shadowing for signature collisions. for (auto signature : collisionTypes) { recordShadowedDeclsAfterSignatureMatch(collisions[signature], curModule, shadowed); } // Check whether we have shadowing for Objective-C initializer collisions. for (auto nominal : objCInitializerCollisionNominals) { recordShadowDeclsAfterObjCInitMatch(objCInitializerCollisions[nominal], shadowed); } } bool swift::removeShadowedDecls(SmallVectorImpl &decls, const ModuleDecl *curModule) { // Collect declarations with the same (full) name. llvm::SmallDenseMap> collidingDeclGroups; bool anyCollisions = false; for (auto decl : decls) { // Record this declaration based on its full name. auto &knownDecls = collidingDeclGroups[decl->getFullName()]; if (!knownDecls.empty()) anyCollisions = true; knownDecls.push_back(decl); } // If nothing collided, we're done. if (!anyCollisions) return false; // Walk through the declarations again, marking any declarations that shadow. llvm::SmallPtrSet shadowed; for (auto decl : decls) { auto known = collidingDeclGroups.find(decl->getFullName()); if (known == collidingDeclGroups.end()) { // We already handled this group. continue; } recordShadowedDecls(known->second, curModule, shadowed); collidingDeclGroups.erase(known); } // If no declarations were shadowed, we're done. if (shadowed.empty()) return false; // Remove shadowed declarations from the list of declarations. bool anyRemoved = false; decls.erase(std::remove_if(decls.begin(), decls.end(), [&](ValueDecl *vd) { if (shadowed.count(vd) > 0) { anyRemoved = true; return true; } return false; }), decls.end()); return anyRemoved; } namespace { enum class DiscriminatorMatch { NoDiscriminator, Matches, Different }; } // end anonymous namespace static DiscriminatorMatch matchDiscriminator(Identifier discriminator, const ValueDecl *value) { if (value->getFormalAccess() > AccessLevel::FilePrivate) return DiscriminatorMatch::NoDiscriminator; auto containingFile = dyn_cast(value->getDeclContext()->getModuleScopeContext()); if (!containingFile) return DiscriminatorMatch::Different; if (discriminator == containingFile->getDiscriminatorForPrivateValue(value)) return DiscriminatorMatch::Matches; return DiscriminatorMatch::Different; } static DiscriminatorMatch matchDiscriminator(Identifier discriminator, LookupResultEntry lookupResult) { return matchDiscriminator(discriminator, lookupResult.getValueDecl()); } template static void filterForDiscriminator(SmallVectorImpl &results, DebuggerClient *debugClient) { Identifier discriminator = debugClient->getPreferredPrivateDiscriminator(); if (discriminator.empty()) return; auto lastMatchIter = std::find_if(results.rbegin(), results.rend(), [discriminator](Result next) -> bool { return matchDiscriminator(discriminator, next) == DiscriminatorMatch::Matches; }); if (lastMatchIter == results.rend()) return; Result lastMatch = *lastMatchIter; auto newEnd = std::remove_if(results.begin(), lastMatchIter.base()-1, [discriminator](Result next) -> bool { return matchDiscriminator(discriminator, next) == DiscriminatorMatch::Different; }); results.erase(newEnd, results.end()); results.push_back(lastMatch); } static void recordLookupOfTopLevelName(DeclContext *topLevelContext, DeclName name, bool isCascading) { auto SF = dyn_cast(topLevelContext); if (!SF) return; auto *nameTracker = SF->getReferencedNameTracker(); if (!nameTracker) return; nameTracker->addTopLevelName(name.getBaseName(), isCascading); } /// Determine the local declaration visibility key for an \c ASTScope in which /// name lookup successfully resolved. static DeclVisibilityKind getLocalDeclVisibilityKind(const ASTScope *scope) { switch (scope->getKind()) { case ASTScopeKind::Preexpanded: case ASTScopeKind::SourceFile: case ASTScopeKind::TypeDecl: case ASTScopeKind::AbstractFunctionDecl: case ASTScopeKind::TypeOrExtensionBody: case ASTScopeKind::AbstractFunctionBody: case ASTScopeKind::DefaultArgument: case ASTScopeKind::PatternBinding: case ASTScopeKind::IfStmt: case ASTScopeKind::GuardStmt: case ASTScopeKind::RepeatWhileStmt: case ASTScopeKind::ForEachStmt: case ASTScopeKind::DoCatchStmt: case ASTScopeKind::SwitchStmt: case ASTScopeKind::Accessors: case ASTScopeKind::TopLevelCode: llvm_unreachable("no local declarations?"); case ASTScopeKind::ExtensionGenericParams: case ASTScopeKind::GenericParams: return DeclVisibilityKind::GenericParameter; case ASTScopeKind::AbstractFunctionParams: case ASTScopeKind::Closure: case ASTScopeKind::PatternInitializer: // lazy var 'self' return DeclVisibilityKind::FunctionParameter; case ASTScopeKind::AfterPatternBinding: case ASTScopeKind::ConditionalClause: case ASTScopeKind::ForEachPattern: case ASTScopeKind::BraceStmt: case ASTScopeKind::CatchStmt: case ASTScopeKind::CaseStmt: return DeclVisibilityKind::LocalVariable; } llvm_unreachable("Unhandled ASTScopeKind in switch."); } /// Retrieve the set of type declarations that are directly referenced from /// the given parsed type representation. static DirectlyReferencedTypeDecls directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc); /// Retrieve the set of type declarations that are directly referenced from /// the given type. static DirectlyReferencedTypeDecls directReferencesForType(Type type); /// Given a set of type declarations, find all of the nominal type declarations /// that they reference, looking through typealiases as appropriate. static TinyPtrVector resolveTypeDeclsToNominal(Evaluator &evaluator, ASTContext &ctx, ArrayRef typeDecls, SmallVectorImpl &modulesFound, bool &anyObject); SelfBounds SelfBoundsFromWhereClauseRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion decl) const { auto *typeDecl = decl.dyn_cast(); auto *protoDecl = dyn_cast_or_null(typeDecl); auto *extDecl = decl.dyn_cast(); DeclContext *dc = protoDecl ? (DeclContext *)protoDecl : (DeclContext *)extDecl; // A protocol or extension 'where' clause can reference associated types of // the protocol itself, so we have to start unqualified lookup from 'dc'. // // However, the right hand side of a 'Self' conformance constraint must be // resolved before unqualified lookup into 'dc' can work, so we make an // exception here and begin lookup from the parent context instead. auto *lookupDC = dc->getParent(); auto requirements = protoDecl ? protoDecl->getTrailingWhereClause() : extDecl->getTrailingWhereClause(); ASTContext &ctx = dc->getASTContext(); SelfBounds result; if (requirements == nullptr) return result; for (const auto &req : requirements->getRequirements()) { // We only care about type constraints. if (req.getKind() != RequirementReprKind::TypeConstraint) continue; // The left-hand side of the type constraint must be 'Self'. bool isSelfLHS = false; if (auto typeRepr = req.getSubjectRepr()) { if (auto identTypeRepr = dyn_cast(typeRepr)) isSelfLHS = (identTypeRepr->getIdentifier() == ctx.Id_Self); } else if (Type type = req.getSubject()) { isSelfLHS = type->isEqual(dc->getSelfInterfaceType()); } if (!isSelfLHS) continue; // Resolve the right-hand side. DirectlyReferencedTypeDecls rhsDecls; if (auto typeRepr = req.getConstraintRepr()) { rhsDecls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, lookupDC); } else if (Type type = req.getConstraint()) { rhsDecls = directReferencesForType(type); } SmallVector modulesFound; auto rhsNominals = resolveTypeDeclsToNominal(evaluator, ctx, rhsDecls, modulesFound, result.anyObject); result.decls.insert(result.decls.end(), rhsNominals.begin(), rhsNominals.end()); } return result; } SelfBounds swift::getSelfBoundsFromWhereClause( llvm::PointerUnion decl) { auto *typeDecl = decl.dyn_cast(); auto *extDecl = decl.dyn_cast(); auto &ctx = typeDecl ? typeDecl->getASTContext() : extDecl->getASTContext(); return evaluateOrDefault(ctx.evaluator, SelfBoundsFromWhereClauseRequest{decl}, {}); } // TODO: change name when ExpUnqualifiedLookup is adopted to // populatePlacesToSearchFromContext static void populateLookupDeclsFromContext(DeclContext *dc, SmallVectorImpl &lookupDecls) { auto nominal = dc->getSelfNominalTypeDecl(); if (!nominal) return; lookupDecls.push_back(nominal); // For a protocol extension, check whether there are additional "Self" // constraints that can affect name lookup. if (dc->getExtendedProtocolDecl()) { auto ext = cast(dc); auto bounds = getSelfBoundsFromWhereClause(ext); for (auto bound : bounds.decls) lookupDecls.push_back(bound); } } TinyPtrVector TypeDeclsFromWhereClauseRequest::evaluate(Evaluator &evaluator, ExtensionDecl *ext) const { ASTContext &ctx = ext->getASTContext(); TinyPtrVector result; for (const auto &req : ext->getGenericParams()->getTrailingRequirements()) { auto resolve = [&](TypeLoc loc) { DirectlyReferencedTypeDecls decls; if (auto *typeRepr = loc.getTypeRepr()) decls = directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext); else if (Type type = loc.getType()) decls = directReferencesForType(type); result.insert(result.end(), decls.begin(), decls.end()); }; switch (req.getKind()) { case RequirementReprKind::TypeConstraint: resolve(req.getSubjectLoc()); resolve(req.getConstraintLoc()); break; case RequirementReprKind::SameType: resolve(req.getFirstTypeLoc()); resolve(req.getSecondTypeLoc()); break; case RequirementReprKind::LayoutConstraint: resolve(req.getSubjectLoc()); break; } } return result; } namespace { /// Determine whether unqualified lookup should look at the members of the /// given nominal type or extension, vs. only looking at type parameters. template bool shouldLookupMembers(D *decl, SourceLoc loc) { // Only look at members of this type (or its inherited types) when // inside the body or a protocol's top-level 'where' clause. (Why the // 'where' clause? Because that's where you put constraints on // inherited associated types.) // When we have no source-location information, we have to perform member // lookup. if (loc.isInvalid() || decl->getBraces().isInvalid()) return true; // Within the braces, always look for members. auto &ctx = decl->getASTContext(); if (ctx.SourceMgr.rangeContainsTokenLoc(decl->getBraces(), loc)) return true; // Within 'where' clause, we can also look for members. if (auto *whereClause = decl->getTrailingWhereClause()) { SourceRange whereClauseRange = whereClause->getSourceRange(); if (whereClauseRange.isValid() && ctx.SourceMgr.rangeContainsTokenLoc(whereClauseRange, loc)) { return true; } } // Don't look at the members. return false; } } // end anonymous namespace UnqualifiedLookup::UnqualifiedLookup(DeclName Name, DeclContext *DC, LazyResolver *TypeResolver, SourceLoc Loc, Options options) : UnqualifiedLookup("dummy", Name, DC, TypeResolver, Loc, options) { assert(ExpUnqualifiedLookup(Name, DC, TypeResolver, Loc, options) .verifyEqual(*this) && "bad refactoring"); } UnqualifiedLookup::UnqualifiedLookup(const char *dummy, DeclName Name, DeclContext *DC, LazyResolver *TypeResolver, SourceLoc Loc, Options options) : IndexOfFirstOuterResult(0) { ModuleDecl &M = *DC->getParentModule(); ASTContext &Ctx = M.getASTContext(); if (!TypeResolver) TypeResolver = Ctx.getLazyResolver(); const SourceManager &SM = Ctx.SourceMgr; DebuggerClient *DebugClient = M.getDebugClient(); auto isOriginallyTypeLookup = options.contains(Flags::TypeLookup); NamedDeclConsumer Consumer(Name, Results, isOriginallyTypeLookup); NLOptions baseNLOptions = NL_UnqualifiedDefault; if (options.contains(Flags::AllowProtocolMembers)) baseNLOptions |= NL_ProtocolMembers; if (isOriginallyTypeLookup) baseNLOptions |= NL_OnlyTypes; if (options.contains(Flags::IgnoreAccessControl)) baseNLOptions |= NL_IgnoreAccessControl; Optional isCascadingUse; if (options.contains(Flags::KnownPrivate)) isCascadingUse = false; SmallVector UnavailableInnerResults; auto shouldReturnBasedOnResults = [&](bool noMoreOuterResults = false) { if (Results.empty()) return false; if (IndexOfFirstOuterResult == 0) IndexOfFirstOuterResult = Results.size(); return !options.contains(Flags::IncludeOuterResults) || noMoreOuterResults; }; if (Loc.isValid() && DC->getParentSourceFile() && DC->getParentSourceFile()->Kind != SourceFileKind::REPL && Ctx.LangOpts.EnableASTScopeLookup) { // Find the source file in which we are performing the lookup. SourceFile &sourceFile = *DC->getParentSourceFile(); // Find the scope from which we will initiate unqualified name lookup. const ASTScope *lookupScope = sourceFile.getScope().findInnermostEnclosingScope(Loc); // Operator lookup is always at module scope. if (Name.isOperator()) { if (!isCascadingUse.hasValue()) { DeclContext *innermostDC = lookupScope->getInnermostEnclosingDeclContext(); isCascadingUse = innermostDC->isCascadingContextForLookup( /*functionsAreNonCascading=*/true); } lookupScope = &sourceFile.getScope(); } // Walk scopes outward from the innermost scope until we find something. DeclContext *selfDC = nullptr; for (auto currentScope = lookupScope; currentScope; currentScope = currentScope->getParent()) { // Perform local lookup within this scope. auto localBindings = currentScope->getLocalBindings(); for (auto local : localBindings) { Consumer.foundDecl(local, getLocalDeclVisibilityKind(currentScope)); } // If we found anything, we're done. if (shouldReturnBasedOnResults()) return; // When we are in the body of a method, get the 'self' declaration. if (currentScope->getKind() == ASTScopeKind::AbstractFunctionBody && currentScope->getAbstractFunctionDecl() ->getDeclContext() ->isTypeContext()) { selfDC = currentScope->getAbstractFunctionDecl(); continue; } // If there is a declaration context associated with this scope, we might // want to look in it. if (auto dc = currentScope->getDeclContext()) { // If we haven't determined whether we have a cascading use, do so now. if (!isCascadingUse.hasValue()) { isCascadingUse = dc->isCascadingContextForLookup( /*functionsAreNonCascading=*/false); } // Pattern binding initializers are only interesting insofar as they // affect lookup in an enclosing nominal type or extension thereof. if (auto *bindingInit = dyn_cast(dc)) { // Lazy variable initializer contexts have a 'self' parameter for // instance member lookup. if (bindingInit->getImplicitSelfDecl()) selfDC = bindingInit; continue; } // Default arguments only have 'static' access to the members of the // enclosing type, if there is one. if (isa(dc)) continue; // Functions/initializers/deinitializers are only interesting insofar as // they affect lookup in an enclosing nominal type or extension thereof. if (isa(dc)) continue; // Subscripts have no lookup of their own. if (isa(dc)) continue; // Closures have no lookup of their own. if (isa(dc)) continue; // Top-level declarations have no lookup of their own. if (isa(dc)) continue; // Typealiases have no lookup of their own. if (isa(dc)) continue; // Lookup in the source file's scope marks the end. if (isa(dc)) { // FIXME: A bit of a hack. DC = dc; break; } // We have a nominal type or an extension thereof. Perform lookup into // the nominal type. auto nominal = dc->getSelfNominalTypeDecl(); if (!nominal) continue; // Dig out the type we're looking into. SmallVector lookupDecls; populateLookupDeclsFromContext(dc, lookupDecls); NLOptions options = baseNLOptions; // Perform lookup into the type. if (isCascadingUse.getValue()) options |= NL_KnownCascadingDependency; else options |= NL_KnownNonCascadingDependency; SmallVector lookup; dc->lookupQualified(lookupDecls, Name, options, lookup); auto startIndex = Results.size(); for (auto result : lookup) { auto *baseDC = dc; if (!isa(result) && selfDC) baseDC = selfDC; Results.push_back(LookupResultEntry(baseDC, result)); } if (!Results.empty()) { // Predicate that determines whether a lookup result should // be unavailable except as a last-ditch effort. auto unavailableLookupResult = [&](const LookupResultEntry &result) { auto &effectiveVersion = Ctx.LangOpts.EffectiveLanguageVersion; return result.getValueDecl() ->getAttrs() .isUnavailableInSwiftVersion(effectiveVersion); }; // If all of the results we just found are unavailable, keep looking. auto begin = Results.begin() + startIndex; if (std::all_of(begin, Results.end(), unavailableLookupResult)) { UnavailableInnerResults.append(begin, Results.end()); Results.erase(begin, Results.end()); } else { if (DebugClient) filterForDiscriminator(Results, DebugClient); if (shouldReturnBasedOnResults()) return; } } // Forget the 'self' declaration. selfDC = nullptr; } } } else { // Never perform local lookup for operators. if (Name.isOperator()) { if (!isCascadingUse.hasValue()) { isCascadingUse = DC->isCascadingContextForLookup(/*functionsAreNonCascading=*/true); } DC = DC->getModuleScopeContext(); } else { // If we are inside of a method, check to see if there are any ivars in // scope, and if so, whether this is a reference to one of them. // FIXME: We should persist this information between lookups. while (!DC->isModuleScopeContext()) { DeclContext *BaseDC = nullptr; DeclContext *MetaBaseDC = nullptr; GenericParamList *GenericParams = nullptr; SmallVector lookupDecls; if (auto *PBI = dyn_cast(DC)) { auto *PBD = PBI->getBinding(); assert(PBD); // Lazy variable initializer contexts have a 'self' parameter for // instance member lookup. if (auto *selfParam = PBI->getImplicitSelfDecl()) { Consumer.foundDecl(selfParam, DeclVisibilityKind::FunctionParameter); if (shouldReturnBasedOnResults()) return; DC = DC->getParent(); populateLookupDeclsFromContext(DC, lookupDecls); MetaBaseDC = DC; BaseDC = PBI; } // Initializers for stored properties of types perform static // lookup into the surrounding context. else if (PBD->getDeclContext()->isTypeContext()) { DC = DC->getParent(); populateLookupDeclsFromContext(DC, lookupDecls); MetaBaseDC = DC; BaseDC = MetaBaseDC; isCascadingUse = DC->isCascadingContextForLookup(false); } // Otherwise, we have an initializer for a global or local property. // There's not much to find here, we'll keep going up to a parent // context. if (!isCascadingUse.hasValue()) isCascadingUse = DC->isCascadingContextForLookup(false); } else if (auto *AFD = dyn_cast(DC)) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. // FIXME: when we can parse and typecheck the function body partially // for code completion, AFD->getBody() check can be removed. if (Loc.isValid() && AFD->getBody()) { if (!isCascadingUse.hasValue()) { isCascadingUse = !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.visit(AFD->getBody()); if (shouldReturnBasedOnResults()) return; if (auto *P = AFD->getImplicitSelfDecl()) localVal.checkValueDecl(P, DeclVisibilityKind::FunctionParameter); localVal.checkParameterList(AFD->getParameters()); if (shouldReturnBasedOnResults()) return; } if (!isCascadingUse.hasValue() || isCascadingUse.getValue()) isCascadingUse = AFD->isCascadingContextForLookup(false); if (AFD->getDeclContext()->isTypeContext()) { populateLookupDeclsFromContext(AFD->getDeclContext(), lookupDecls); BaseDC = AFD; MetaBaseDC = AFD->getDeclContext(); DC = DC->getParent(); // If we're not in the body of the function (for example, we // might be type checking a default argument expression and // performing name lookup from there), the base declaration // is the nominal type, not 'self'. if (!AFD->isImplicit() && Loc.isValid() && AFD->getBodySourceRange().isValid() && !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)) { BaseDC = MetaBaseDC; } } // Look in the generic parameters after checking our local declaration. GenericParams = AFD->getGenericParams(); } else if (auto *ACE = dyn_cast(DC)) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. if (Loc.isValid()) { if (auto *CE = dyn_cast(ACE)) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); if (auto body = CE->getBody()) localVal.visit(body); if (shouldReturnBasedOnResults()) return; if (auto params = CE->getParameters()) localVal.checkParameterList(params); if (shouldReturnBasedOnResults()) return; } } if (!isCascadingUse.hasValue()) isCascadingUse = ACE->isCascadingContextForLookup(false); } else if (auto *ED = dyn_cast(DC)) { if (shouldLookupMembers(ED, Loc)) populateLookupDeclsFromContext(ED, lookupDecls); BaseDC = ED; MetaBaseDC = ED; if (!isCascadingUse.hasValue()) isCascadingUse = ED->isCascadingContextForLookup(false); } else if (auto *ND = dyn_cast(DC)) { if (shouldLookupMembers(ND, Loc)) populateLookupDeclsFromContext(ND, lookupDecls); BaseDC = DC; MetaBaseDC = DC; if (!isCascadingUse.hasValue()) isCascadingUse = ND->isCascadingContextForLookup(false); } else if (auto I = dyn_cast(DC)) { // In a default argument, skip immediately out of both the // initializer and the function. isCascadingUse = false; DC = I->getParent()->getParent(); continue; } else { assert(isa(DC) || isa(DC) || isa(DC) || isa(DC)); if (!isCascadingUse.hasValue()) isCascadingUse = DC->isCascadingContextForLookup(false); } // If we're inside a function context, we've already moved to // the parent DC, so we have to check the function's generic // parameters first. if (GenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(GenericParams); if (shouldReturnBasedOnResults()) return; } // Check the generic parameters of our context. GenericParamList *dcGenericParams = nullptr; if (auto nominal = dyn_cast(DC)) dcGenericParams = nominal->getGenericParams(); else if (auto ext = dyn_cast(DC)) dcGenericParams = ext->getGenericParams(); else if (auto subscript = dyn_cast(DC)) dcGenericParams = subscript->getGenericParams(); while (dcGenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(dcGenericParams); if (shouldReturnBasedOnResults()) return; dcGenericParams = dcGenericParams->getOuterParameters(); } if (BaseDC && !lookupDecls.empty()) { NLOptions options = baseNLOptions; if (isCascadingUse.getValue()) options |= NL_KnownCascadingDependency; else options |= NL_KnownNonCascadingDependency; SmallVector Lookup; DC->lookupQualified(lookupDecls, Name, options, Lookup); bool FoundAny = false; auto startIndex = Results.size(); for (auto Result : Lookup) { // Classify this declaration. FoundAny = true; // Types are formally members of the metatype. if (auto TD = dyn_cast(Result)) { Results.push_back(LookupResultEntry(MetaBaseDC, Result)); continue; } Results.push_back(LookupResultEntry(BaseDC, Result)); } if (FoundAny) { // Predicate that determines whether a lookup result should // be unavailable except as a last-ditch effort. auto unavailableLookupResult = [&](const LookupResultEntry &result) { auto &effectiveVersion = Ctx.LangOpts.EffectiveLanguageVersion; return result.getValueDecl() ->getAttrs() .isUnavailableInSwiftVersion(effectiveVersion); }; // If all of the results we found are unavailable, keep looking. auto begin = Results.begin() + startIndex; if (std::all_of(begin, Results.end(), unavailableLookupResult)) { UnavailableInnerResults.append(begin, Results.end()); Results.erase(begin, Results.end()); } else { if (DebugClient) filterForDiscriminator(Results, DebugClient); if (shouldReturnBasedOnResults()) return; } } } DC = DC->getParentForLookup(); } if (!isCascadingUse.hasValue()) isCascadingUse = true; } if (auto SF = dyn_cast(DC)) { if (Loc.isValid()) { // Look for local variables in top-level code; normally, the parser // resolves these for us, but it can't do the right thing for // local types. namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkSourceFile(*SF); if (shouldReturnBasedOnResults()) return; } } } // TODO: Does the debugger client care about compound names? if (Name.isSimpleName() && DebugClient && DebugClient->lookupOverrides(Name.getBaseName(), DC, Loc, isOriginallyTypeLookup, Results)) return; recordLookupOfTopLevelName(DC, Name, isCascadingUse.getValue()); recordedSF = dyn_cast(DC); recordedName = Name; recordedIsCascadingUse = isCascadingUse.getValue(); // Add private imports to the extra search list. SmallVector extraImports; if (auto FU = dyn_cast(DC)) FU->getImportedModules(extraImports, ModuleDecl::ImportFilter::Private); using namespace namelookup; SmallVector CurModuleResults; auto resolutionKind = isOriginallyTypeLookup ? ResolutionKind::TypesOnly : ResolutionKind::Overloadable; lookupInModule(&M, {}, Name, CurModuleResults, NLKind::UnqualifiedLookup, resolutionKind, TypeResolver, DC, extraImports); // Always perform name shadowing for type lookup. if (options.contains(Flags::TypeLookup)) { removeShadowedDecls(CurModuleResults, &M); } for (auto VD : CurModuleResults) Results.push_back(LookupResultEntry(VD)); if (DebugClient) filterForDiscriminator(Results, DebugClient); // Now add any names the DebugClient knows about to the lookup. if (Name.isSimpleName() && DebugClient) DebugClient->lookupAdditions(Name.getBaseName(), DC, Loc, isOriginallyTypeLookup, Results); // If we've found something, we're done. if (shouldReturnBasedOnResults(/*noMoreOuterResults=*/true)) return; // If we still haven't found anything, but we do have some // declarations that are "unavailable in the current Swift", drop // those in. Results = std::move(UnavailableInnerResults); if (shouldReturnBasedOnResults(/*noMoreOuterResults=*/true)) return; if (!Name.isSimpleName()) return; // Look for a module with the given name. if (Name.isSimpleName(M.getName())) { Results.push_back(LookupResultEntry(&M)); if (shouldReturnBasedOnResults(/*noMoreOuterResults=*/true)) return; } ModuleDecl *desiredModule = Ctx.getLoadedModule(Name.getBaseIdentifier()); if (!desiredModule && Name == Ctx.TheBuiltinModule->getName()) desiredModule = Ctx.TheBuiltinModule; if (desiredModule) { forAllVisibleModules(DC, [&](const ModuleDecl::ImportedModule &import) -> bool { if (import.second == desiredModule) { Results.push_back(LookupResultEntry(import.second)); return false; } return true; }); } // Make sure we've recorded the inner-result-boundary. (void)shouldReturnBasedOnResults(/*noMoreOuterResults=*/true); } TypeDecl* UnqualifiedLookup::getSingleTypeResult() { if (Results.size() != 1) return nullptr; return dyn_cast(Results.back().getValueDecl()); } ExpUnqualifiedLookup::PlacesToSearch::PlacesToSearch( DeclContext *fromWhence, DeclContext *whereNonTypesAreMembers, DeclContext *whereTypesAreMembers, DeclContext *placesHolder) : fromWhence(fromWhence), whereNonTypesAreMembers(whereNonTypesAreMembers), whereTypesAreMembers(whereTypesAreMembers) { populateLookupDeclsFromContext(placesHolder, places); } void ExpUnqualifiedLookup::PlacesToSearch::dump() const { llvm::errs() << "fromWhence: "; fromWhence->dumpContext(); llvm::errs() << "whereNonTypesAreMembers: "; whereNonTypesAreMembers->dumpContext(); llvm::errs() << "whereTypesAreMembers: "; whereTypesAreMembers->dumpContext(); llvm::errs() << "places: "; for (const auto *D : places) D->dump(); llvm::errs() << "\n"; } namespace { class UnqualifiedLookupFactory { using Flags = UnqualifiedLookup::Flags; using Options = UnqualifiedLookup::Options; using PlacesToSearch = ExpUnqualifiedLookup::PlacesToSearch; using PerScopeLookupState = ExpUnqualifiedLookup::PerScopeLookupState; const DeclName Name; DeclContext *const DC; ModuleDecl &M; const ASTContext &Ctx; LazyResolver *const TypeResolver; const SourceLoc Loc; const SourceManager &SM; /// Used to find the file-local names. DebuggerClient *const DebugClient; const Options options; const bool isOriginallyTypeLookup; NamedDeclConsumer Consumer; const NLOptions baseNLOptions; SmallVectorImpl &Results; size_t &IndexOfFirstOuterResult; // For debugging: SourceFile const *&recordedSF; DeclName &recordedName; bool &recordedIsCascadingUse; std::vector &breadcrumbs; SmallVector UnavailableInnerResults; public: UnqualifiedLookupFactory(DeclName Name, DeclContext *const DC, LazyResolver *TypeResolver, SourceLoc Loc, Options options, ExpUnqualifiedLookup &lookupToBeCreated) : Name(Name), DC(DC), M(*DC->getParentModule()), Ctx(M.getASTContext()), TypeResolver(TypeResolver ? TypeResolver : Ctx.getLazyResolver()), Loc(Loc), SM(Ctx.SourceMgr), DebugClient(M.getDebugClient()), options(options), isOriginallyTypeLookup(options.contains(Flags::TypeLookup)), Consumer(Name, lookupToBeCreated.Results, isOriginallyTypeLookup), baseNLOptions(computeBaseNLOptions(options, isOriginallyTypeLookup)), Results(lookupToBeCreated.Results), IndexOfFirstOuterResult(lookupToBeCreated.IndexOfFirstOuterResult), recordedSF(lookupToBeCreated.recordedSF), recordedName(lookupToBeCreated.recordedName), recordedIsCascadingUse(lookupToBeCreated.recordedIsCascadingUse), breadcrumbs(lookupToBeCreated.breadcrumbs) {} void fillInLookup() { const Optional isCascadingUse = options.contains(Flags::KnownPrivate) ? Optional(false) : None; // Never perform local lookup for operators. std::pair dcAndIsCascadingUse = shouldUseASTScopeLookup() ? astScopeBasedLookup(DC, isCascadingUse) : Name.isOperator() ? operatorLookup(DC, isCascadingUse) : nonASTScopeBasedLookup(DC, isCascadingUse); if (!dcAndIsCascadingUse.first) return; // TODO: Does the debugger client care about compound names? if (Name.isSimpleName() && DebugClient && DebugClient->lookupOverrides(Name.getBaseName(), dcAndIsCascadingUse.first, Loc, isOriginallyTypeLookup, Results)) return; finishLookupRENAME(dcAndIsCascadingUse.first, dcAndIsCascadingUse.second); } private: /// Return nullptr if done with whole enchilada and isCascadingUse std::pair astScopeBasedLookup(DeclContext *dc, Optional isCascadingUse) { const std::pair> lookupScopeAndIsCascadingUse = Name.isOperator() ? operatorScopeForASTScopeLookup(dc, isCascadingUse) : nonoperatorScopeForASTScopeLookup(dc, isCascadingUse); // Walk scopes outward from the innermost scope until we find something. DeclContext *selfDC = nullptr; Optional currentIsCascadingUse = lookupScopeAndIsCascadingUse.second; for (auto currentScope = lookupScopeAndIsCascadingUse.first; currentScope; currentScope = currentScope->getParent()) { auto stausSelfDCFinalDCIsCascadingUse = lookInScope(currentScope, selfDC, dc, currentIsCascadingUse); currentIsCascadingUse = std::get<3>(stausSelfDCFinalDCIsCascadingUse); switch (std::get<0>(stausSelfDCFinalDCIsCascadingUse)) { case ScopeLookupResult::next: break; case ScopeLookupResult::stop: return std::make_pair(std::get<2>(stausSelfDCFinalDCIsCascadingUse), std::get<3>(stausSelfDCFinalDCIsCascadingUse).getValue()); case ScopeLookupResult::finished: return std::make_pair(nullptr, false); } selfDC = std::get<1>(stausSelfDCFinalDCIsCascadingUse); dc = std::get<2>(stausSelfDCFinalDCIsCascadingUse); currentIsCascadingUse = std::get<3>(stausSelfDCFinalDCIsCascadingUse); } llvm_unreachable("impossible"); } using ScopeLookupResult = ExpUnqualifiedLookup::ScopeLookupResult; static NLOptions computeBaseNLOptions(const UnqualifiedLookup::Options options, const bool isOriginallyTypeLookup) { NLOptions baseNLOptions = NL_UnqualifiedDefault; if (options.contains(Flags::AllowProtocolMembers)) baseNLOptions |= NL_ProtocolMembers; if (isOriginallyTypeLookup) baseNLOptions |= NL_OnlyTypes; if (options.contains(Flags::IgnoreAccessControl)) baseNLOptions |= NL_IgnoreAccessControl; return baseNLOptions; } /// Return true if done with lookup. bool isFinishedWithLookupNowThatIsAboutToLookForOuterResults( bool noMoreOuterResults = false) { if (Results.empty()) return false; if (IndexOfFirstOuterResult == 0) IndexOfFirstOuterResult = Results.size(); return !options.contains(Flags::IncludeOuterResults) || noMoreOuterResults; } bool shouldUseASTScopeLookup() const { return Loc.isValid() && DC->getParentSourceFile() && DC->getParentSourceFile()->Kind != SourceFileKind::REPL && Ctx.LangOpts.EnableASTScopeLookup; } std::pair operatorScopeForASTScopeLookup(DeclContext *dc, Optional isCascadingUse) { // Find the source file in which we are performing the lookup. SourceFile &sourceFile = *dc->getParentSourceFile(); // Find the scope from which we will initiate unqualified name lookup. const ASTScope *lookupScope = sourceFile.getScope().findInnermostEnclosingScope(Loc); // Operator lookup is always at module scope. return std::make_pair( &sourceFile.getScope(), updateIsCascadingForOperator( lookupScope->getInnermostEnclosingDeclContext(), isCascadingUse)); } std::pair > nonoperatorScopeForASTScopeLookup(DeclContext *dc, Optional isCascadingUse) const { // Find the source file in which we are performing the lookup. SourceFile &sourceFile = *dc->getParentSourceFile(); // Find the scope from which we will initiate unqualified name lookup. const ASTScope *lookupScope = sourceFile.getScope().findInnermostEnclosingScope(Loc); return std::make_pair(lookupScope, isCascadingUse); } /// Return status and new selfDC and new DC std::tuple> lookInScope(const ASTScope *const currentScope, DeclContext *selfDC, DeclContext *dc, const Optional isCascadingUse) { // Perform local lookup within this scope. auto localBindings = currentScope->getLocalBindings(); for (auto local : localBindings) { Consumer.foundDecl(local, getLocalDeclVisibilityKind(currentScope)); } // If we found anything, we're done. if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return std::make_tuple(ScopeLookupResult::finished, selfDC, dc, false); // When we are in the body of a method, get the 'self' declaration. if (currentScope->getKind() == ASTScopeKind::AbstractFunctionBody && currentScope->getAbstractFunctionDecl() ->getDeclContext() ->isTypeContext()) { selfDC = currentScope->getAbstractFunctionDecl(); return std::make_tuple(ScopeLookupResult::next, selfDC, dc, isCascadingUse); } // If there is a declaration context associated with this scope, we might // want to look in it. if (auto scopeDC = currentScope->getDeclContext()) return lookIntoDeclarationContext(scopeDC, selfDC, dc, isCascadingUse); return std::make_tuple(ScopeLookupResult::next, selfDC, dc, isCascadingUse); } /// Returns status and selfDC and DC std::tuple lookIntoDeclarationContext(DeclContext *dc, DeclContext *selfDC, DeclContext *wasDC, Optional isCascadingUse) { // If we haven't determined whether we have a cascading use, do so now. const bool isCascadingUseResult = isCascadingUse.hasValue() ? isCascadingUse.getValue() : dc->isCascadingContextForLookup(/*functionsAreNonCascading=*/false); // Pattern binding initializers are only interesting insofar as they // affect lookup in an enclosing nominal type or extension thereof. if (auto *bindingInit = dyn_cast(dc)) { // Lazy variable initializer contexts have a 'self' parameter for // instance member lookup. if (bindingInit->getImplicitSelfDecl()) selfDC = bindingInit; return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); } // Default arguments only have 'static' access to the members of the // enclosing type, if there is one. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Functions/initializers/deinitializers are only interesting insofar as // they affect lookup in an enclosing nominal type or extension thereof. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Subscripts have no lookup of their own. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Closures have no lookup of their own. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Top-level declarations have no lookup of their own. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Typealiases have no lookup of their own. if (isa(dc)) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Lookup in the source file's scope marks the end. if (isa(dc)) { // FIXME: A bit of a hack. return std::make_tuple(ScopeLookupResult::stop, selfDC, dc, isCascadingUseResult); } // We have a nominal type or an extension thereof. Perform lookup into // the nominal type. auto nominal = dc->getSelfNominalTypeDecl(); if (!nominal) return std::make_tuple(ScopeLookupResult::next, selfDC, wasDC, isCascadingUseResult); // Dig out the type we're looking into. using LookupDecls = SmallVector; LookupDecls lookupDecls; populateLookupDeclsFromContext(dc, lookupDecls); NLOptions options = baseNLOptions; // Perform lookup into the type. if (isCascadingUseResult) options |= NL_KnownCascadingDependency; else options |= NL_KnownNonCascadingDependency; SmallVector lookup; dc->lookupQualified(lookupDecls, Name, options, lookup); auto startIndex = Results.size(); for (auto result : lookup) { auto *baseDC = dc; if (!isa(result) && selfDC) baseDC = selfDC; Results.push_back(LookupResultEntry(baseDC, result)); } if (!Results.empty()) { // Predicate that determines whether a lookup result should // be unavailable except as a last-ditch effort. auto unavailableLookupResult = [&](const LookupResultEntry &result) { auto &effectiveVersion = Ctx.LangOpts.EffectiveLanguageVersion; return result.getValueDecl()->getAttrs().isUnavailableInSwiftVersion( effectiveVersion); }; // If all of the results we just found are unavailable, keep looking. auto begin = Results.begin() + startIndex; if (std::all_of(begin, Results.end(), unavailableLookupResult)) { UnavailableInnerResults.append(begin, Results.end()); Results.erase(begin, Results.end()); } else { if (DebugClient) filterForDiscriminator(Results, DebugClient); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return std::make_tuple(ScopeLookupResult::finished, selfDC, wasDC, isCascadingUseResult); } } // Forget the 'self' declaration. selfDC = nullptr; return std::make_tuple(ScopeLookupResult::next, selfDC, dc, isCascadingUseResult); } // TODO: Use me more often bool updateIsCascadingForOperator(const DeclContext *const dc, Optional isCascadingUse) { return isCascadingUse.hasValue() ? isCascadingUse.getValue() : dc->isCascadingContextForLookup(/*functionsAreNonCascading=*/true); } // return nullptr if lookup done std::pair operatorLookup(DeclContext *dc, Optional isCascadingUse) { auto *msc = dc->getModuleScopeContext(); return std::make_pair(addLocalVariableResults(msc) ? nullptr : msc, updateIsCascadingForOperator(dc, isCascadingUse)); } /// Return nullptr if done looking up. std::pair nonASTScopeBasedLookup(DeclContext *const dc, const Optional isCascadingUseArg) { // If we are inside of a method, check to see if there are any ivars in // scope, and if so, whether this is a reference to one of them. // FIXME: We should persist this information between lookups. DeclContext *nextDC = dc; auto isCascadingUse = isCascadingUseArg; while (!nextDC->isModuleScopeContext()) { auto resultAndDCAndIsCascadingUse = lookupInOneDeclContext(nextDC, isCascadingUse); DeclContext *oldDC = nextDC; // CLEAN UP nextDC = std::get<1>(resultAndDCAndIsCascadingUse); isCascadingUse = std::get<2>(resultAndDCAndIsCascadingUse); switch (std::get<0>(resultAndDCAndIsCascadingUse)) { case ScopeLookupResult::next: assert(nextDC != oldDC && "non-termination"); continue; case ScopeLookupResult::stop: break; case ScopeLookupResult::finished: return std::make_pair(nullptr, false); } break; } return std::make_pair(addLocalVariableResults(nextDC) ? nullptr : nextDC, isCascadingUse.hasValue() ? isCascadingUse.getValue(): true); } /// Return the next context to search. std::tuple> lookupInOneDeclContext(DeclContext *dc, const Optional isCascadingUseArg) { const PerScopeLookupState results = lookupInAppropriateContext(dc, isCascadingUseArg); breadcrumbs.push_back(results); switch (results.result) { case ScopeLookupResult::next: break; case ScopeLookupResult::stop: return std::make_tuple(ScopeLookupResult::next, results.childOfNextDC, results.isCascadingUse); case ScopeLookupResult::finished: return std::make_tuple(ScopeLookupResult::finished, results.childOfNextDC, results.isCascadingUse); } if (addGenericParametersHereAndInEnclosingScopes(results.childOfNextDC)) return std::make_tuple(ScopeLookupResult::finished, results.childOfNextDC, results.isCascadingUse); if (results.placesToSearch.hasValue() && !results.placesToSearch.getValue().empty()) { auto startIndexOfInnerResults = Results.size(); searchPlacesToSearch(std::move(results.placesToSearch.getValue()), Name, results.isCascadingUse.getValue(), baseNLOptions, results.childOfNextDC); if (handleUnavailableInnerResults(startIndexOfInnerResults)) return std::make_tuple(ScopeLookupResult::finished, results.childOfNextDC, results.isCascadingUse); } // TODO: What if !BaseDC && lookupDecls non-empty? DeclContext *nextDC = results.childOfNextDC->getParentForLookup(); return std::make_tuple(ScopeLookupResult::next, nextDC, results.isCascadingUse); } /// Check the generic parameters of our context. /// Return true if done with lookup /// TODO: Factor with addGenericParmeters below bool addGenericParametersHereAndInEnclosingScopes(DeclContext *dc) { for (GenericParamList *dcGenericParams = getGenericParams(dc); dcGenericParams; dcGenericParams = dcGenericParams->getOuterParameters()) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(dcGenericParams); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return true; } return false; } /// Consume generic parameters void addGenericParametersForFunction(AbstractFunctionDecl *AFD) { // If we're inside a function context, we've already moved to // the parent DC, so we have to check the function's generic // parameters first. GenericParamList *GenericParams = AFD->getGenericParams(); if (GenericParams) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkGenericParams(GenericParams); } } static GenericParamList *getGenericParams(const DeclContext *const dc) { if (auto nominal = dyn_cast(dc)) return nominal->getGenericParams(); if (auto ext = dyn_cast(dc)) return ext->getGenericParams(); if (auto subscript = dyn_cast(dc)) return subscript->getGenericParams(); return nullptr; } PerScopeLookupState lookupInAppropriateContext(DeclContext *dc, Optional isCascadingUse) { if (auto *PBI = dyn_cast(dc)) return lookupInPatternBindingInitializer(PBI, isCascadingUse); if (auto *AFD = dyn_cast(dc)) return lookupInFunctionDecl(AFD, isCascadingUse); if (auto *ACE = dyn_cast(dc)) return lookupInClosure(ACE, isCascadingUse); if (auto *ED = dyn_cast(dc)) return lookupInExtension(ED, isCascadingUse); if (auto *ND = dyn_cast(dc)) return lookupInNominalType(ND, isCascadingUse); if (auto I = dyn_cast(dc)) return lookupInDefaultArgumentInitializer(I, isCascadingUse); return lookupInMiscContext(dc, isCascadingUse); } PerScopeLookupState lookupInPatternBindingInitializer(PatternBindingInitializer *PBI, Optional isCascadingUse) { auto *PBD = PBI->getBinding(); assert(PBD); // Lazy variable initializer contexts have a 'self' parameter for // instance member lookup. if (auto *selfParam = PBI->getImplicitSelfDecl()) { Consumer.foundDecl(selfParam, DeclVisibilityKind::FunctionParameter); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return PerScopeLookupState{ ScopeLookupResult::finished, PBI, None, // FACTOR THIS LINE isCascadingUse.hasValue() ? isCascadingUse.getValue() : PBI->isCascadingContextForLookup(false)}; DeclContext *const parent = PBI->getParent(); return PerScopeLookupState{ ScopeLookupResult::next, parent, PlacesToSearch(parent, PBI, parent, parent), isCascadingUse.hasValue() ? isCascadingUse.getValue() : PBI->isCascadingContextForLookup(false)}; } // Initializers for stored properties of types perform static // lookup into the surrounding context. if (PBD->getDeclContext()->isTypeContext()) { DeclContext *const surroundingContext = PBI->getParent(); return PerScopeLookupState{ ScopeLookupResult::next, surroundingContext, PlacesToSearch(surroundingContext, surroundingContext, surroundingContext, surroundingContext), surroundingContext->isCascadingContextForLookup(false)}; } // Otherwise, we have an initializer for a global or local property. // There's not much to find here, we'll keep going up to a parent // context. return PerScopeLookupState{ScopeLookupResult::next, PBI, None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : PBI->isCascadingContextForLookup(false)}; } PerScopeLookupState lookupInFunctionDecl(AbstractFunctionDecl *AFD, Optional isCascadingUse) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. // FIXME: when we can parse and typecheck the function body partially // for code completion, AFD->getBody() check can be removed. if (Loc.isValid() && AFD->getBody()) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.visit(AFD->getBody()); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return PerScopeLookupState{ ScopeLookupResult::finished, AFD, None, // FACTOR INTO A FN isCascadingUse.hasValue() ? isCascadingUse.getValue() : !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)}; if (auto *P = AFD->getImplicitSelfDecl()) localVal.checkValueDecl(P, DeclVisibilityKind::FunctionParameter); localVal.checkParameterList(AFD->getParameters()); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return PerScopeLookupState{ ScopeLookupResult::finished, AFD, None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)}; } const bool returnValueForIsCascadingUse = AFD->isCascadingContextForLookup(false) && (isCascadingUse.hasValue() ? isCascadingUse.getValue() : !Loc.isValid() || !AFD->getBody() || !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc)); if (AFD->getDeclContext()->isTypeContext()) { DeclContext *fnDeclContext = AFD->getDeclContext(); DeclContext *fnParent = AFD->getParent(); addGenericParametersForFunction(AFD); return PerScopeLookupState{ isFinishedWithLookupNowThatIsAboutToLookForOuterResults() ? ScopeLookupResult::finished : ScopeLookupResult::next, fnParent, PlacesToSearch( fnParent, // If we're not in the body of the function (for example, we // might be type checking a default argument expression and // performing name lookup from there), the base declaration // is the nominal type, not 'self'. isOutsideBodyOfFunction(AFD) ? fnDeclContext : AFD, fnDeclContext, AFD->getDeclContext()), returnValueForIsCascadingUse}; } // Look in the generic parameters after checking our local declaration. addGenericParametersForFunction(AFD); return PerScopeLookupState{ isFinishedWithLookupNowThatIsAboutToLookForOuterResults() ? ScopeLookupResult::finished : ScopeLookupResult::next, AFD, None, returnValueForIsCascadingUse}; } PerScopeLookupState lookupInClosure(AbstractClosureExpr *ACE, Optional isCascadingUse) { // Look for local variables; normally, the parser resolves these // for us, but it can't do the right thing inside local types. if (Loc.isValid()) { if (auto *CE = dyn_cast(ACE)) { namelookup::FindLocalVal localVal(SM, Loc, Consumer); if (auto body = CE->getBody()) localVal.visit(body); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) { return PerScopeLookupState{ScopeLookupResult::finished, ACE, None, isCascadingUse}; } if (auto params = CE->getParameters()) localVal.checkParameterList(params); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) { return PerScopeLookupState{ScopeLookupResult::finished, ACE, None, isCascadingUse}; } } } return PerScopeLookupState{ScopeLookupResult::next, ACE, None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : ACE->isCascadingContextForLookup(false)}; } PerScopeLookupState lookupInExtension(ExtensionDecl *ED, Optional isCascadingUse) { return PerScopeLookupState{ ScopeLookupResult::next, ED, shouldLookupMembers(ED, Loc) ? Optional(PlacesToSearch(ED, ED, ED, ED)) : None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : ED->isCascadingContextForLookup(false)}; } PerScopeLookupState lookupInNominalType(NominalTypeDecl *ND, Optional isCascadingUse) { return PerScopeLookupState{ ScopeLookupResult::next, ND, shouldLookupMembers(ND, Loc) ? Optional(PlacesToSearch(ND, ND, ND, ND)) : None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : ND->isCascadingContextForLookup(false)}; } PerScopeLookupState lookupInDefaultArgumentInitializer(DefaultArgumentInitializer *I, Optional isCascadingUse) { // In a default argument, skip immediately out of both the // initializer and the function. return PerScopeLookupState{ScopeLookupResult::stop, I->getParent()->getParent(), None, false}; } bool isOutsideBodyOfFunction(const AbstractFunctionDecl *const AFD) const { return !AFD->isImplicit() && Loc.isValid() && AFD->getBodySourceRange().isValid() && !SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc); } PerScopeLookupState lookupInMiscContext(DeclContext *dc, Optional isCascadingUse) { assert(isa(dc) || isa(dc) || isa(dc) || isa(dc)); return PerScopeLookupState{ScopeLookupResult::next, dc, None, isCascadingUse.hasValue() ? isCascadingUse.getValue() : dc->isCascadingContextForLookup(false)}; } /// return true if lookup is done bool addLocalVariableResults(DeclContext *dc) { if (auto SF = dyn_cast(dc)) { if (Loc.isValid()) { // Look for local variables in top-level code; normally, the parser // resolves these for us, but it can't do the right thing for // local types. namelookup::FindLocalVal localVal(SM, Loc, Consumer); localVal.checkSourceFile(*SF); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults()) return true; } } return false; } /// Return true if found any // TODO: make member fn of PlacesToSearch, take ref to Result as arg void searchPlacesToSearch(PlacesToSearch placesToSearch, DeclName Name, const bool isCascadingUse, const NLOptions baseNLOptions, DeclContext *contextForLookup) { const NLOptions options = baseNLOptions | (isCascadingUse ? NL_KnownCascadingDependency : NL_KnownNonCascadingDependency); SmallVector Lookup; contextForLookup->lookupQualified(placesToSearch.places, Name, options, Lookup); for (auto Result : Lookup) Results.push_back(LookupResultEntry( placesToSearch.whereValueIsMember(Result), Result)); } /// Return true if finished with lookup bool handleUnavailableInnerResults(const size_t startIndexOfInnerResults) { // An optimization: assert(Results.size() >= startIndexOfInnerResults); if (Results.size() == startIndexOfInnerResults) return false; // Predicate that determines whether a lookup result should // be unavailable except as a last-ditch effort. auto unavailableLookupResult = [&](const LookupResultEntry &result) { auto &effectiveVersion = Ctx.LangOpts.EffectiveLanguageVersion; return result.getValueDecl()->getAttrs().isUnavailableInSwiftVersion( effectiveVersion); }; // If all of the results we found are unavailable, keep looking. auto begin = Results.begin() + startIndexOfInnerResults; if (std::all_of(begin, Results.end(), unavailableLookupResult)) { UnavailableInnerResults.append(begin, Results.end()); Results.erase(begin, Results.end()); return false; } if (DebugClient) filterForDiscriminator(Results, DebugClient); return isFinishedWithLookupNowThatIsAboutToLookForOuterResults(); } void finishLookupRENAME(DeclContext *const dc, const bool isCascadingUse) { recordLookupOfTopLevelName(dc, Name, isCascadingUse); recordedSF = dyn_cast(dc); recordedName = Name; recordedIsCascadingUse = isCascadingUse; // Add private imports to the extra search list. SmallVector extraImports; if (auto FU = dyn_cast(dc)) FU->getImportedModules(extraImports, ModuleDecl::ImportFilter::Private); using namespace namelookup; SmallVector CurModuleResults; auto resolutionKind = isOriginallyTypeLookup ? ResolutionKind::TypesOnly : ResolutionKind::Overloadable; lookupInModule(&M, {}, Name, CurModuleResults, NLKind::UnqualifiedLookup, resolutionKind, TypeResolver, dc, extraImports); // Always perform name shadowing for type lookup. if (options.contains(Flags::TypeLookup)) { removeShadowedDecls(CurModuleResults, &M); } for (auto VD : CurModuleResults) Results.push_back(LookupResultEntry(VD)); if (DebugClient) filterForDiscriminator(Results, DebugClient); // Now add any names the DebugClient knows about to the lookup. if (Name.isSimpleName() && DebugClient) DebugClient->lookupAdditions(Name.getBaseName(), dc, Loc, isOriginallyTypeLookup, Results); // If we've found something, we're done. if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults( /*noMoreOuterResults=*/true)) return; // If we still haven't found anything, but we do have some // declarations that are "unavailable in the current Swift", drop // those in. Results = std::move(UnavailableInnerResults); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults( /*noMoreOuterResults=*/true)) return; if (!Name.isSimpleName()) return; // Look for a module with the given name. if (Name.isSimpleName(M.getName())) { Results.push_back(LookupResultEntry(&M)); if (isFinishedWithLookupNowThatIsAboutToLookForOuterResults( /*noMoreOuterResults=*/true)) return; } ModuleDecl *desiredModule = Ctx.getLoadedModule(Name.getBaseIdentifier()); if (!desiredModule && Name == Ctx.TheBuiltinModule->getName()) desiredModule = Ctx.TheBuiltinModule; if (desiredModule) { forAllVisibleModules( dc, [&](const ModuleDecl::ImportedModule &import) -> bool { if (import.second == desiredModule) { Results.push_back(LookupResultEntry(import.second)); return false; } return true; }); } // Make sure we've recorded the inner-result-boundary. (void)isFinishedWithLookupNowThatIsAboutToLookForOuterResults( /*noMoreOuterResults=*/true); } }; } // namespace ExpUnqualifiedLookup::ExpUnqualifiedLookup(DeclName Name, DeclContext *const DC, LazyResolver *TypeResolver, SourceLoc Loc, Options options) : IndexOfFirstOuterResult(0) { UnqualifiedLookupFactory(Name, DC, TypeResolver, Loc, options, *this) .fillInLookup(); } TypeDecl* ExpUnqualifiedLookup::getSingleTypeResult() { if (Results.size() != 1) return nullptr; return dyn_cast(Results.back().getValueDecl()); } bool ExpUnqualifiedLookup::verifyEqual(const UnqualifiedLookup &other) const { assert(Results.size() == other.Results.size()); for (size_t i: indices(Results)) { const auto &e = Results[i]; const auto &oe = other.Results[i]; assert(e.getValueDecl() == oe.getValueDecl()); assert(e.getDeclContext() == oe.getDeclContext()); //unsigned printContext(llvm::raw_ostream &OS, unsigned indent = 0, // bool onlyAPartialLine = false) const; assert(e.getBaseDecl() == oe.getBaseDecl()); } assert ( IndexOfFirstOuterResult == other.IndexOfFirstOuterResult); assert(recordedSF == other.recordedSF); assert(recordedName == other.recordedName); if (recordedIsCascadingUse) assert(other.recordedIsCascadingUse); else assert(!other.recordedIsCascadingUse); return true; } void ExpUnqualifiedLookup::dumpBreadcrumbs() const { auto &e = llvm::errs(); for (size_t i : indices(breadcrumbs)) { e << i << "\n"; const PerScopeLookupState &s = breadcrumbs[i]; s.dump(); } } void ExpUnqualifiedLookup::PerScopeLookupState::dump() const { auto &e = llvm::errs(); switch (result) { case ScopeLookupResult::next: e << "next: "; break; case ScopeLookupResult::stop: e << "stop: "; break; case ScopeLookupResult::finished: e << "finished: "; break; } e << " dc: "; childOfNextDC->dumpContext(); if (placesToSearch.hasValue()) placesToSearch.getValue().dump(); } #pragma mark Member lookup table void LazyMemberLoader::anchor() {} void LazyConformanceLoader::anchor() {} /// Lookup table used to store members of a nominal type (and its extensions) /// for fast retrieval. class swift::MemberLookupTable { /// The last extension that was included within the member lookup table's /// results. ExtensionDecl *LastExtensionIncluded = nullptr; /// The type of the internal lookup table. typedef llvm::DenseMap> LookupTable; /// Lookup table mapping names to the set of declarations with that name. LookupTable Lookup; public: /// Create a new member lookup table. explicit MemberLookupTable(ASTContext &ctx); /// Update a lookup table with members from newly-added extensions. void updateLookupTable(NominalTypeDecl *nominal); /// Add the given member to the lookup table. void addMember(Decl *members); /// Add the given members to the lookup table. void addMembers(DeclRange members); /// Iterator into the lookup table. typedef LookupTable::iterator iterator; iterator begin() { return Lookup.begin(); } iterator end() { return Lookup.end(); } iterator find(DeclName name) { return Lookup.find(name); } void dump(llvm::raw_ostream &os) const { os << "LastExtensionIncluded:\n"; if (LastExtensionIncluded) LastExtensionIncluded->printContext(os, 2); else os << " nullptr\n"; os << "Lookup:\n "; for (auto &pair : Lookup) { pair.getFirst().print(os) << ":\n "; for (auto &decl : pair.getSecond()) { os << "- "; decl->dumpRef(os); os << "\n "; } } os << "\n"; } LLVM_ATTRIBUTE_DEPRECATED(void dump() const LLVM_ATTRIBUTE_USED, "only for use within the debugger") { dump(llvm::errs()); } // Mark all Decls in this table as not-resident in a table, drop // references to them. Should only be called when this was not fully-populated // from an IterableDeclContext. void clear() { // LastExtensionIncluded would only be non-null if this was populated from // an IterableDeclContext (though it might still be null in that case). assert(LastExtensionIncluded == nullptr); for (auto const &i : Lookup) { for (auto d : i.getSecond()) { d->setAlreadyInLookupTable(false); } } Lookup.clear(); } // Only allow allocation of member lookup tables using the allocator in // ASTContext or by doing a placement new. void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignof(MemberLookupTable)) { return C.Allocate(Bytes, Alignment); } void *operator new(size_t Bytes, void *Mem) { assert(Mem); return Mem; } }; namespace { /// Stores the set of Objective-C methods with a given selector within the /// Objective-C method lookup table. struct StoredObjCMethods { /// The generation count at which this list was last updated. unsigned Generation = 0; /// The set of methods with the given selector. llvm::TinyPtrVector Methods; }; } // end anonymous namespace /// Class member lookup table, which is a member lookup table with a second /// table for lookup based on Objective-C selector. class ClassDecl::ObjCMethodLookupTable : public llvm::DenseMap, StoredObjCMethods> { public: // Only allow allocation of member lookup tables using the allocator in // ASTContext or by doing a placement new. void *operator new(size_t Bytes, ASTContext &C, unsigned Alignment = alignof(MemberLookupTable)) { return C.Allocate(Bytes, Alignment); } void *operator new(size_t Bytes, void *Mem) { assert(Mem); return Mem; } }; MemberLookupTable::MemberLookupTable(ASTContext &ctx) { // Register a cleanup with the ASTContext to call the lookup table // destructor. ctx.addCleanup([this]() { this->~MemberLookupTable(); }); } void MemberLookupTable::addMember(Decl *member) { // Only value declarations matter. auto vd = dyn_cast(member); if (!vd) return; // @_implements members get added under their declared name. auto A = vd->getAttrs().getAttribute(); // Unnamed entities w/o @_implements synonyms cannot be found by name lookup. if (!A && !vd->hasName()) return; // If this declaration is already in the lookup table, don't add it // again. if (vd->isAlreadyInLookupTable()) { return; } vd->setAlreadyInLookupTable(); // Add this declaration to the lookup set under its compound name and simple // name. vd->getFullName().addToLookupTable(Lookup, vd); // And if given a synonym, under that name too. if (A) A->getMemberName().addToLookupTable(Lookup, vd); } void MemberLookupTable::addMembers(DeclRange members) { for (auto member : members) { addMember(member); } } void MemberLookupTable::updateLookupTable(NominalTypeDecl *nominal) { // If the last extension we included is the same as the last known extension, // we're already up-to-date. if (LastExtensionIncluded == nominal->LastExtension) return; // Add members from each of the extensions that we have not yet visited. for (auto next = LastExtensionIncluded ? LastExtensionIncluded->NextExtension.getPointer() : nominal->FirstExtension; next; (LastExtensionIncluded = next,next = next->NextExtension.getPointer())) { addMembers(next->getMembers()); } } void NominalTypeDecl::addedMember(Decl *member) { // Remember if we added a destructor. if (auto *CD = dyn_cast(this)) if (isa(member)) CD->setHasDestructor(); // If we have a lookup table, add the new member to it. if (LookupTable.getPointer()) { LookupTable.getPointer()->addMember(member); } } void NominalTypeDecl::addedExtension(ExtensionDecl * ext) { if (hasLazyMembers()) setLookupTablePopulated(false); } void ExtensionDecl::addedMember(Decl *member) { if (NextExtension.getInt()) { auto nominal = getExtendedNominal(); if (!nominal) return; if (nominal->LookupTable.getPointer() && nominal->isLookupTablePopulated()) { // Make sure we have the complete list of extensions. // FIXME: This is completely unnecessary. We want to determine whether // our own extension has already been included in the lookup table. (void)nominal->getExtensions(); nominal->LookupTable.getPointer()->addMember(member); } } } // For lack of anywhere more sensible to put it, here's a diagram of the pieces // involved in finding members and extensions of a NominalTypeDecl. // // ┌────────────────────────────┬─┐ // │IterableDeclContext │ │ ┌─────────────────────────────┐ // │------------------- │ │ │┌───────────────┬┐ ▼ // │Decl *LastDecl ───────────┼─┼─────┘│Decl ││ ┌───────────────┬┐ // │Decl *FirstDecl ───────────┼─┼─────▶│---- ││ │Decl ││ // │ │ │ │Decl *NextDecl├┼─▶│---- ││ // │bool HasLazyMembers │ │ ├───────────────┘│ │Decl *NextDecl ││ // │IterableDeclContextKind Kind│ │ │ │ ├───────────────┘│ // │ │ │ │ValueDecl │ │ │ // ├────────────────────────────┘ │ │--------- │ │ValueDecl │ // │ │ │DeclName Name │ │--------- │ // │NominalTypeDecl │ └────────────────┘ │DeclName Name │ // │--------------- │ ▲ └────────────────┘ // │ExtensionDecl *FirstExtension─┼────────┐ │ ▲ // │ExtensionDecl *LastExtension ─┼───────┐│ │ └───┐ // │ │ ││ └──────────────────────┐│ // │MemberLookupTable *LookupTable├─┐ ││ ││ // │bool LookupTableComplete │ │ ││ ┌─────────────────┐ ││ // └──────────────────────────────┘ │ ││ │ExtensionDecl │ ││ // │ ││ │------------- │ ││ // ┌─────────────┘ │└────▶│ExtensionDecl │ ││ // │ │ │ *NextExtension ├──┐ ││ // ▼ │ └─────────────────┘ │ ││ // ┌─────────────────────────────────────┐│ ┌─────────────────┐ │ ││ // │MemberLookupTable ││ │ExtensionDecl │ │ ││ // │----------------- ││ │------------- │ │ ││ // │ExtensionDecl *LastExtensionIncluded ├┴─────▶│ExtensionDecl │◀─┘ ││ // │ │ │ *NextExtension │ ││ // │┌───────────────────────────────────┐│ └─────────────────┘ ││ // ││DenseMap LookupTable││ ││ // ││-----------------------------------││ ┌──────────────────────────┐ ││ // ││[NameA] TinyPtrVector ││ │TinyPtrVector│ ││ // ││[NameB] TinyPtrVector ││ │--------------------------│ ││ // ││[NameC] TinyPtrVector─┼┼─▶│[0] ValueDecl * ─────┼─┘│ // │└───────────────────────────────────┘│ │[1] ValueDecl * ─────┼──┘ // └─────────────────────────────────────┘ └──────────────────────────┘ // // The HasLazyMembers, Kind, and LookupTableComplete fields are packed into // PointerIntPairs so don't go grepping for them; but for purposes of // illustration they are effectively their own fields. // // MemberLookupTable is populated en-masse when the IterableDeclContext's // (IDC's) list of Decls is populated. But MemberLookupTable can also be // populated incrementally by one-name-at-a-time lookups by lookupDirect, in // which case those Decls are _not_ added to the IDC's list. They are cached in // the loader they come from, lifecycle-wise, and are added to the // MemberLookupTable to accelerate subsequent retrieval, but the IDC is not // considered populated until someone calls getMembers(). // // If the IDC list is later populated and/or an extension is added _after_ // MemberLookupTable is constructed (and possibly has entries in it), // MemberLookupTable is purged and reconstructed from IDC's list. // // In all lookup routines, the 'ignoreNewExtensions' flag means that // lookup should only use the set of extensions already observed. static bool populateLookupTableEntryFromLazyIDCLoader(ASTContext &ctx, MemberLookupTable &LookupTable, DeclName name, IterableDeclContext *IDC) { if (IDC->isLoadingLazyMembers()) { return false; } IDC->setLoadingLazyMembers(true); auto ci = ctx.getOrCreateLazyIterableContextData(IDC, /*lazyLoader=*/nullptr); if (auto res = ci->loader->loadNamedMembers(IDC, name.getBaseName(), ci->memberData)) { IDC->setLoadingLazyMembers(false); if (auto s = ctx.Stats) { ++s->getFrontendCounters().NamedLazyMemberLoadSuccessCount; } for (auto d : *res) { LookupTable.addMember(d); } return false; } else { IDC->setLoadingLazyMembers(false); if (auto s = ctx.Stats) { ++s->getFrontendCounters().NamedLazyMemberLoadFailureCount; } return true; } } static void populateLookupTableEntryFromCurrentMembersWithoutLoading( ASTContext &ctx, MemberLookupTable &LookupTable, DeclName name, IterableDeclContext *IDC) { for (auto m : IDC->getCurrentMembersWithoutLoading()) { if (auto v = dyn_cast(m)) { if (v->getFullName().matchesRef(name.getBaseName())) { LookupTable.addMember(m); } } } } static bool populateLookupTableEntryFromExtensions(ASTContext &ctx, MemberLookupTable &table, NominalTypeDecl *nominal, DeclName name, bool ignoreNewExtensions) { if (!ignoreNewExtensions) { for (auto e : nominal->getExtensions()) { if (e->wasDeserialized() || e->hasClangNode()) { if (populateLookupTableEntryFromLazyIDCLoader(ctx, table, name, e)) { return true; } } else { populateLookupTableEntryFromCurrentMembersWithoutLoading(ctx, table, name, e); } } } return false; } bool NominalTypeDecl::isLookupTablePopulated() const { return LookupTable.getInt(); } void NominalTypeDecl::setLookupTablePopulated(bool value) { LookupTable.setInt(value); } void NominalTypeDecl::prepareLookupTable(bool ignoreNewExtensions) { // If we haven't allocated the lookup table yet, do so now. if (!LookupTable.getPointer()) { auto &ctx = getASTContext(); LookupTable.setPointer(new (ctx) MemberLookupTable(ctx)); } if (hasLazyMembers()) { // Lazy members: if the table needs population, populate the table _only // from those members already in the IDC member list_ such as implicits or // globals-as-members, then update table entries from the extensions that // have the same names as any such initial-population members. if (!isLookupTablePopulated()) { setLookupTablePopulated(true); LookupTable.getPointer()->addMembers(getCurrentMembersWithoutLoading()); llvm::SetVector baseNamesPresent; for (auto entry : *LookupTable.getPointer()) { baseNamesPresent.insert(entry.getFirst().getBaseName()); } for (auto baseName : baseNamesPresent) { populateLookupTableEntryFromExtensions(getASTContext(), *LookupTable.getPointer(), this, baseName, ignoreNewExtensions); } } } else { // No lazy members: if the table needs population, populate the table // en-masse; and in either case update the extensions. if (!isLookupTablePopulated()) { setLookupTablePopulated(true); LookupTable.getPointer()->addMembers(getMembers()); } if (!ignoreNewExtensions) { LookupTable.getPointer()->updateLookupTable(this); } } } void NominalTypeDecl::makeMemberVisible(ValueDecl *member) { if (!LookupTable.getPointer()) { auto &ctx = getASTContext(); LookupTable.setPointer(new (ctx) MemberLookupTable(ctx)); } LookupTable.getPointer()->addMember(member); } static TinyPtrVector maybeFilterOutAttrImplements(TinyPtrVector decls, DeclName name, bool includeAttrImplements) { if (includeAttrImplements) return decls; TinyPtrVector result; for (auto V : decls) { // Filter-out any decl that doesn't have the name we're looking for // (asserting as a consistency-check that such entries all have // @_implements attrs for the name!) if (V->getFullName().matchesRef(name)) { result.push_back(V); } else { auto A = V->getAttrs().getAttribute(); assert(A && A->getMemberName().matchesRef(name)); } } return result; } TinyPtrVector NominalTypeDecl::lookupDirect( DeclName name, OptionSet flags) { ASTContext &ctx = getASTContext(); if (auto s = ctx.Stats) { ++s->getFrontendCounters().NominalTypeLookupDirectCount; } // We only use NamedLazyMemberLoading when a user opts-in and we have // not yet loaded all the members into the IDC list in the first place. bool useNamedLazyMemberLoading = (ctx.LangOpts.NamedLazyMemberLoading && hasLazyMembers()); bool ignoreNewExtensions = flags.contains(LookupDirectFlags::IgnoreNewExtensions); bool includeAttrImplements = flags.contains(LookupDirectFlags::IncludeAttrImplements); // FIXME: At present, lazy member is not able to find inherited constructors // in imported classes, because SwiftDeclConverter::importInheritedConstructors() // is only called via ClangImporter::Implementation::loadAllMembers(). if (hasClangNode() && name.getBaseName() == DeclBaseName::createConstructor()) useNamedLazyMemberLoading = false; LLVM_DEBUG(llvm::dbgs() << getNameStr() << ".lookupDirect(" << name << ", " << ignoreNewExtensions << ")" << ", isLookupTablePopulated()=" << isLookupTablePopulated() << ", hasLazyMembers()=" << hasLazyMembers() << ", useNamedLazyMemberLoading=" << useNamedLazyMemberLoading << "\n"); // We check the LookupTable at most twice, possibly treating a miss in the // first try as a cache-miss that we then do a cache-fill on, and retry. for (int i = 0; i < 2; ++i) { // First, if we're _not_ doing NamedLazyMemberLoading, we make sure we've // populated the IDC and brought it up to date with any extensions. This // will flip the hasLazyMembers() flag to false as well. if (!useNamedLazyMemberLoading) { // It's possible that the lookup table exists but has information in it // that is either currently out of date or soon to be out of date. // This can happen two ways: // // - We've not yet indexed the members we have (isLookupTablePopulated() // is zero). // // - We've still got more lazy members left to load; this can happen // even if we _did_ index some members. // // In either of these cases, we want to reset the table to empty and // mark it as needing reconstruction. if (LookupTable.getPointer() && (hasLazyMembers() || !isLookupTablePopulated())) { LookupTable.getPointer()->clear(); setLookupTablePopulated(false); } (void)getMembers(); // Make sure we have the complete list of members (in this nominal and in // all extensions). if (!ignoreNewExtensions) { for (auto E : getExtensions()) (void)E->getMembers(); } } // Next, in all cases, prepare the lookup table for use, possibly // repopulating it from the IDC if the IDC member list has just grown. prepareLookupTable(ignoreNewExtensions); // Look for a declaration with this name. auto known = LookupTable.getPointer()->find(name); // We found something; return it. if (known != LookupTable.getPointer()->end()) return maybeFilterOutAttrImplements(known->second, name, includeAttrImplements); // If we have no more second chances, stop now. if (!useNamedLazyMemberLoading || i > 0) break; // If we get here, we had a cache-miss and _are_ using // NamedLazyMemberLoading. Try to populate a _single_ entry in the // MemberLookupTable from both this nominal and all of its extensions, and // retry. Any failure to load here flips the useNamedLazyMemberLoading to // false, and we fall back to loading all members during the retry. auto &Table = *LookupTable.getPointer(); if (populateLookupTableEntryFromLazyIDCLoader(ctx, Table, name, this) || populateLookupTableEntryFromExtensions(ctx, Table, this, name, ignoreNewExtensions)) { useNamedLazyMemberLoading = false; } } // None of our attempts found anything. return { }; } void ClassDecl::createObjCMethodLookup() { assert(!ObjCMethodLookup && "Already have an Objective-C member table"); auto &ctx = getASTContext(); ObjCMethodLookup = new (ctx) ObjCMethodLookupTable(); // Register a cleanup with the ASTContext to call the lookup table // destructor. ctx.addCleanup([this]() { this->ObjCMethodLookup->~ObjCMethodLookupTable(); }); } MutableArrayRef ClassDecl::lookupDirect(ObjCSelector selector, bool isInstance) { if (!ObjCMethodLookup) { createObjCMethodLookup(); } // If any modules have been loaded since we did the search last (or if we // hadn't searched before), look in those modules, too. auto &stored = (*ObjCMethodLookup)[{selector, isInstance}]; ASTContext &ctx = getASTContext(); if (ctx.getCurrentGeneration() > stored.Generation) { ctx.loadObjCMethods(this, selector, isInstance, stored.Generation, stored.Methods); stored.Generation = ctx.getCurrentGeneration(); } return { stored.Methods.begin(), stored.Methods.end() }; } void ClassDecl::recordObjCMethod(AbstractFunctionDecl *method, ObjCSelector selector) { if (!ObjCMethodLookup) { createObjCMethodLookup(); } // Record the method. bool isInstanceMethod = method->isObjCInstanceMethod(); auto &vec = (*ObjCMethodLookup)[{selector, isInstanceMethod}].Methods; // In a non-empty vector, we could have duplicates or conflicts. if (!vec.empty()) { // Check whether we have a duplicate. This only checks more than one // element in ill-formed code, so the linear search is acceptable. if (std::find(vec.begin(), vec.end(), method) != vec.end()) return; if (vec.size() == 1) { // We have a conflict. getASTContext().recordObjCMethodConflict(this, selector, isInstanceMethod); } } else { // Record the first method that has this selector. getASTContext().recordObjCMethod(method); } vec.push_back(method); } /// Configure name lookup for the given declaration context and options. /// /// This utility is used by qualified name lookup. static void configureLookup(const DeclContext *dc, NLOptions &options, ReferencedNameTracker *&tracker, bool &isLookupCascading) { auto &ctx = dc->getASTContext(); if (ctx.isAccessControlDisabled()) options |= NL_IgnoreAccessControl; // Find the dependency tracker we'll need for this lookup. tracker = nullptr; if (auto containingSourceFile = dyn_cast(dc->getModuleScopeContext())) { tracker = containingSourceFile->getReferencedNameTracker(); } auto checkLookupCascading = [dc, options]() -> Optional { switch (static_cast(options & NL_KnownDependencyMask)) { case 0: return dc->isCascadingContextForLookup( /*functionsAreNonCascading=*/false); case NL_KnownNonCascadingDependency: return false; case NL_KnownCascadingDependency: return true; case NL_KnownNoDependency: return None; default: // FIXME: Use llvm::CountPopulation_64 when that's declared constexpr. #if defined(__clang__) || defined(__GNUC__) static_assert(__builtin_popcountll(NL_KnownDependencyMask) == 2, "mask should only include four values"); #endif llvm_unreachable("mask only includes four values"); } }; // Determine whether a lookup here will cascade. isLookupCascading = false; if (tracker) { if (auto maybeLookupCascade = checkLookupCascading()) isLookupCascading = maybeLookupCascade.getValue(); else tracker = nullptr; } } /// Determine whether the given declaration is an acceptable lookup /// result when searching from the given DeclContext. static bool isAcceptableLookupResult(const DeclContext *dc, NLOptions options, ValueDecl *decl, bool onlyCompleteObjectInits) { // Filter out designated initializers, if requested. if (onlyCompleteObjectInits) { if (auto ctor = dyn_cast(decl)) { if (isa(ctor->getDeclContext()) && !ctor->isInheritable()) return false; } else { return false; } } // Ignore stub implementations. if (auto ctor = dyn_cast(decl)) { if (ctor->hasStubImplementation()) return false; } // Check access. if (!(options & NL_IgnoreAccessControl)) { return decl->isAccessibleFrom(dc); } return true; } /// Only name lookup has gathered a set of results, perform any necessary /// steps to prune the result set before returning it to the caller. static bool finishLookup(const DeclContext *dc, NLOptions options, SmallVectorImpl &decls) { // If we're supposed to remove overridden declarations, do so now. if (options & NL_RemoveOverridden) removeOverriddenDecls(decls); // If we're supposed to remove shadowed/hidden declarations, do so now. ModuleDecl *M = dc->getParentModule(); if (options & NL_RemoveNonVisible) removeShadowedDecls(decls, M); if (auto *debugClient = M->getDebugClient()) filterForDiscriminator(decls, debugClient); // We're done. Report success/failure. return !decls.empty(); } /// Inspect the given type to determine which nominal type declarations it /// directly references, to facilitate name lookup into those types. static void extractDirectlyReferencedNominalTypes( Type type, SmallVectorImpl &decls) { if (auto nominal = type->getAnyNominal()) { decls.push_back(nominal); return; } if (auto unbound = type->getAs()) { if (auto nominal = dyn_cast(unbound->getDecl())) decls.push_back(nominal); return; } if (auto archetypeTy = type->getAs()) { // Look in the protocols to which the archetype conforms (always). for (auto proto : archetypeTy->getConformsTo()) decls.push_back(proto); // Look into the superclasses of this archetype. if (auto superclass = archetypeTy->getSuperclass()) { if (auto superclassDecl = superclass->getClassOrBoundGenericClass()) decls.push_back(superclassDecl); } return; } if (auto compositionTy = type->getAs()) { auto layout = compositionTy->getExistentialLayout(); for (auto proto : layout.getProtocols()) { auto *protoDecl = proto->getDecl(); decls.push_back(protoDecl); } if (auto superclass = layout.explicitSuperclass) { auto *superclassDecl = superclass->getClassOrBoundGenericClass(); if (superclassDecl) decls.push_back(superclassDecl); } return; } llvm_unreachable("Not a type containing nominal types?"); } bool DeclContext::lookupQualified(Type type, DeclName member, NLOptions options, LazyResolver *typeResolver, SmallVectorImpl &decls) const { using namespace namelookup; assert(decls.empty() && "additive lookup not supported"); // Handle AnyObject lookup. if (type->isAnyObject()) return lookupAnyObject(member, options, decls); // Handle lookup in a module. if (auto moduleTy = type->getAs()) return lookupQualified(moduleTy->getModule(), member, options, decls); // Figure out which nominal types we will look into. SmallVector nominalTypesToLookInto; extractDirectlyReferencedNominalTypes(type, nominalTypesToLookInto); return lookupQualified(nominalTypesToLookInto, member, options, decls); } bool DeclContext::lookupQualified(ArrayRef typeDecls, DeclName member, NLOptions options, SmallVectorImpl &decls) const { using namespace namelookup; assert(decls.empty() && "additive lookup not supported"); // Configure lookup and dig out the tracker. ReferencedNameTracker *tracker = nullptr; bool isLookupCascading; configureLookup(this, options, tracker, isLookupCascading); // Tracking for the nominal types we'll visit. SmallVector stack; llvm::SmallPtrSet visited; bool sawClassDecl = false; // Add the given nominal type to the stack. auto addNominalType = [&](NominalTypeDecl *nominal) { if (!visited.insert(nominal).second) return false; if (isa(nominal)) sawClassDecl = true; stack.push_back(nominal); return true; }; // Add all of the nominal types to the stack. for (auto nominal : typeDecls) { addNominalType(nominal); } // Whether we only want to return complete object initializers. bool onlyCompleteObjectInits = false; // Visit all of the nominal types we know about, discovering any others // we need along the way. auto &ctx = getASTContext(); auto typeResolver = ctx.getLazyResolver(); bool wantProtocolMembers = (options & NL_ProtocolMembers); while (!stack.empty()) { auto current = stack.back(); stack.pop_back(); if (tracker) tracker->addUsedMember({current, member.getBaseName()},isLookupCascading); // Make sure we've resolved implicit members, if we need them. if (typeResolver) { if (member.getBaseName() == DeclBaseName::createConstructor()) typeResolver->resolveImplicitConstructors(current); typeResolver->resolveImplicitMember(current, member); } // Look for results within the current nominal type and its extensions. bool currentIsProtocol = isa(current); auto flags = OptionSet(); if (options & NL_IncludeAttributeImplements) flags |= NominalTypeDecl::LookupDirectFlags::IncludeAttrImplements; for (auto decl : current->lookupDirect(member, flags)) { // If we're performing a type lookup, don't even attempt to validate // the decl if its not a type. if ((options & NL_OnlyTypes) && !isa(decl)) continue; if (isAcceptableLookupResult(this, options, decl, onlyCompleteObjectInits)) decls.push_back(decl); } // Visit superclass. if (auto classDecl = dyn_cast(current)) { // If we're looking for initializers, only look at the superclass if the // current class permits inheritance. Even then, only find complete // object initializers. bool visitSuperclass = true; if (member.getBaseName() == DeclBaseName::createConstructor()) { if (classDecl->inheritsSuperclassInitializers(typeResolver)) onlyCompleteObjectInits = true; else visitSuperclass = false; } if (visitSuperclass) { if (auto superclassDecl = classDecl->getSuperclassDecl()) if (visited.insert(superclassDecl).second) stack.push_back(superclassDecl); } } // If we're not looking at a protocol and we're not supposed to // visit the protocols that this type conforms to, skip the next // step. if (!wantProtocolMembers && !currentIsProtocol) continue; SmallVector protocols; if (auto *protoDecl = dyn_cast(current)) { // If we haven't seen a class declaration yet, look into the protocol. if (!sawClassDecl) { if (auto superclassDecl = protoDecl->getSuperclassDecl()) { visited.insert(superclassDecl); stack.push_back(superclassDecl); } } // Collect inherited protocols. for (auto inheritedProto : protoDecl->getInheritedProtocols()) { addNominalType(inheritedProto); } } else { // Collect the protocols to which the nominal type conforms. for (auto proto : current->getAllProtocols()) { if (visited.insert(proto).second) { stack.push_back(proto); } } // For a class, we don't need to visit the protocol members of the // superclass: that's already handled. if (isa(current)) wantProtocolMembers = false; } } return finishLookup(this, options, decls); } bool DeclContext::lookupQualified(ModuleDecl *module, DeclName member, NLOptions options, SmallVectorImpl &decls) const { using namespace namelookup; // Configure lookup and dig out the tracker. ReferencedNameTracker *tracker = nullptr; bool isLookupCascading; configureLookup(this, options, tracker, isLookupCascading); ASTContext &ctx = getASTContext(); auto topLevelScope = getModuleScopeContext(); if (module == topLevelScope->getParentModule()) { if (tracker) { recordLookupOfTopLevelName(topLevelScope, member, isLookupCascading); } lookupInModule(module, /*accessPath=*/{}, member, decls, NLKind::QualifiedLookup, ResolutionKind::Overloadable, ctx.getLazyResolver(), topLevelScope); } else { // Note: This is a lookup into another module. Unless we're compiling // multiple modules at once, or if the other module re-exports this one, // it shouldn't be possible to have a dependency from that module on // anything in this one. // Perform the lookup in all imports of this module. forAllVisibleModules(this, [&](const ModuleDecl::ImportedModule &import) -> bool { if (import.second != module) return true; lookupInModule(import.second, import.first, member, decls, NLKind::QualifiedLookup, ResolutionKind::Overloadable, ctx.getLazyResolver(), topLevelScope); // If we're able to do an unscoped lookup, we see everything. No need // to keep going. return !import.first.empty(); }); } llvm::SmallPtrSet knownDecls; decls.erase(std::remove_if(decls.begin(), decls.end(), [&](ValueDecl *vd) -> bool { // If we're performing a type lookup, skip non-types. if ((options & NL_OnlyTypes) && !isa(vd)) return true; return !knownDecls.insert(vd).second; }), decls.end()); return finishLookup(this, options, decls); } bool DeclContext::lookupAnyObject(DeclName member, NLOptions options, SmallVectorImpl &decls) const { using namespace namelookup; assert(decls.empty() && "additive lookup not supported"); // Configure lookup and dig out the tracker. ReferencedNameTracker *tracker = nullptr; bool isLookupCascading; configureLookup(this, options, tracker, isLookupCascading); // Record this lookup. if (tracker) tracker->addDynamicLookupName(member.getBaseName(), isLookupCascading); // Type-only lookup won't find anything on AnyObject. if (options & NL_OnlyTypes) return false; // Collect all of the visible declarations. SmallVector allDecls; forAllVisibleModules(this, [&](ModuleDecl::ImportedModule import) { import.second->lookupClassMember(import.first, member, allDecls); }); // For each declaration whose context is not something we've // already visited above, add it to the list of declarations. llvm::SmallPtrSet knownDecls; for (auto decl : allDecls) { // If the declaration is not @objc, it cannot be called dynamically. if (!decl->isObjC()) continue; // If the declaration has an override, name lookup will also have // found the overridden method. Skip this declaration, because we // prefer the overridden method. if (decl->getOverriddenDecl()) continue; auto dc = decl->getDeclContext(); auto nominal = dc->getSelfNominalTypeDecl(); assert(nominal && "Couldn't find nominal type?"); (void)nominal; // If we didn't see this declaration before, and it's an acceptable // result, add it to the list. // declaration to the list. if (knownDecls.insert(decl).second && isAcceptableLookupResult(this, options, decl, /*onlyCompleteObjectInits=*/false)) decls.push_back(decl); } return finishLookup(this, options, decls); } void DeclContext::lookupAllObjCMethods( ObjCSelector selector, SmallVectorImpl &results) const { // Collect all of the methods with this selector. forAllVisibleModules(this, [&](ModuleDecl::ImportedModule import) { import.second->lookupObjCMethods(selector, results); }); // Filter out duplicates. llvm::SmallPtrSet visited; results.erase( std::remove_if(results.begin(), results.end(), [&](AbstractFunctionDecl *func) -> bool { return !visited.insert(func).second; }), results.end()); } /// Given a set of type declarations, find all of the nominal type declarations /// that they reference, looking through typealiases as appropriate. static TinyPtrVector resolveTypeDeclsToNominal(Evaluator &evaluator, ASTContext &ctx, ArrayRef typeDecls, SmallVectorImpl &modulesFound, bool &anyObject, llvm::SmallPtrSetImpl &typealiases) { TinyPtrVector nominalDecls; for (auto typeDecl : typeDecls) { // Nominal type declarations get copied directly. if (auto nominalDecl = dyn_cast(typeDecl)) { nominalDecls.push_back(nominalDecl); continue; } // Recursively resolve typealiases. if (auto typealias = dyn_cast(typeDecl)) { // FIXME: Ad hoc recursion breaking, so we don't look through the // same typealias multiple times. if (!typealiases.insert(typealias).second) continue; auto underlyingTypeReferences = evaluateOrDefault(evaluator, UnderlyingTypeDeclsReferencedRequest{typealias}, {}); auto underlyingNominalReferences = resolveTypeDeclsToNominal(evaluator, ctx, underlyingTypeReferences, modulesFound, anyObject, typealiases); nominalDecls.insert(nominalDecls.end(), underlyingNominalReferences.begin(), underlyingNominalReferences.end()); // Recognize Swift.AnyObject directly. if (typealias->getName().is("AnyObject")) { // TypeRepr version: Builtin.AnyObject if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { if (auto compound = dyn_cast(typeRepr)) { auto components = compound->getComponents(); if (components.size() == 2 && components[0]->getIdentifier().is("Builtin") && components[1]->getIdentifier().is("AnyObject")) { anyObject = true; } } } // Type version: an empty class-bound existential. if (auto type = typealias->getUnderlyingTypeLoc().getType()) { if (type->isAnyObject()) anyObject = true; } } continue; } // Keep track of modules we see. if (auto module = dyn_cast(typeDecl)) { modulesFound.push_back(module); continue; } // Make sure we didn't miss some interesting kind of type declaration. assert(isa(typeDecl)); } return nominalDecls; } static TinyPtrVector resolveTypeDeclsToNominal(Evaluator &evaluator, ASTContext &ctx, ArrayRef typeDecls, SmallVectorImpl &modulesFound, bool &anyObject) { llvm::SmallPtrSet typealiases; return resolveTypeDeclsToNominal(evaluator, ctx, typeDecls, modulesFound, anyObject, typealiases); } /// Perform unqualified name lookup for types at the given location. static DirectlyReferencedTypeDecls directReferencesForUnqualifiedTypeLookup(ASTContext &ctx, DeclName name, SourceLoc loc, DeclContext *dc) { DirectlyReferencedTypeDecls results; UnqualifiedLookup::Options options = UnqualifiedLookup::Flags::TypeLookup; UnqualifiedLookup lookup(name, dc, ctx.getLazyResolver(), loc, options); for (const auto &result : lookup.Results) { if (auto typeDecl = dyn_cast(result.getValueDecl())) results.push_back(typeDecl); } return results; } /// Perform qualified name lookup for types. static DirectlyReferencedTypeDecls directReferencesForQualifiedTypeLookup(Evaluator &evaluator, ASTContext &ctx, ArrayRef baseTypes, DeclName name, DeclContext *dc) { DirectlyReferencedTypeDecls result; auto addResults = [&result](ArrayRef found){ for (auto decl : found){ assert(isa(decl) && "Lookup should only have found type declarations"); result.push_back(cast(decl)); } }; { // Look into the base types. SmallVector members; auto options = NL_RemoveNonVisible | NL_OnlyTypes; // Look through the type declarations we were given, resolving them down // to nominal type declarations, module declarations, and SmallVector moduleDecls; bool anyObject = false; auto nominalTypeDecls = resolveTypeDeclsToNominal(ctx.evaluator, ctx, baseTypes, moduleDecls, anyObject); dc->lookupQualified(nominalTypeDecls, name, options, members); // Search all of the modules. for (auto module : moduleDecls) { auto innerOptions = options; innerOptions &= ~NL_RemoveOverridden; innerOptions &= ~NL_RemoveNonVisible; dc->lookupQualified(module, name, innerOptions, members); } addResults(members); } return result; } /// Determine the types directly referenced by the given identifier type. static DirectlyReferencedTypeDecls directReferencesForIdentTypeRepr(Evaluator &evaluator, ASTContext &ctx, IdentTypeRepr *ident, DeclContext *dc) { DirectlyReferencedTypeDecls current; bool firstComponent = true; for (const auto &component : ident->getComponentRange()) { // If we already set a declaration, use it. if (auto typeDecl = component->getBoundDecl()) { current = {1, typeDecl}; continue; } // For the first component, perform unqualified name lookup. if (current.empty()) { current = directReferencesForUnqualifiedTypeLookup(ctx, component->getIdentifier(), component->getIdLoc(), dc); // If we didn't find anything, fail now. if (current.empty()) return current; firstComponent = false; continue; } // For subsequent components, perform qualified name lookup. current = directReferencesForQualifiedTypeLookup(evaluator, ctx, current, component->getIdentifier(), dc); if (current.empty()) return current; } return current; } static DirectlyReferencedTypeDecls directReferencesForTypeRepr(Evaluator &evaluator, ASTContext &ctx, TypeRepr *typeRepr, DeclContext *dc) { switch (typeRepr->getKind()) { case TypeReprKind::Array: return {1, ctx.getArrayDecl()}; case TypeReprKind::Attributed: { auto attributed = cast(typeRepr); return directReferencesForTypeRepr(evaluator, ctx, attributed->getTypeRepr(), dc); } case TypeReprKind::Composition: { DirectlyReferencedTypeDecls result; auto composition = cast(typeRepr); for (auto component : composition->getTypes()) { auto componentResult = directReferencesForTypeRepr(evaluator, ctx, component, dc); result.insert(result.end(), componentResult.begin(), componentResult.end()); } return result; } case TypeReprKind::CompoundIdent: case TypeReprKind::GenericIdent: case TypeReprKind::SimpleIdent: return directReferencesForIdentTypeRepr(evaluator, ctx, cast(typeRepr), dc); case TypeReprKind::Dictionary: return { 1, ctx.getDictionaryDecl()}; case TypeReprKind::Tuple: { auto tupleRepr = cast(typeRepr); if (tupleRepr->isParenType()) { return directReferencesForTypeRepr(evaluator, ctx, tupleRepr->getElementType(0), dc); } return { }; } case TypeReprKind::Error: case TypeReprKind::Function: case TypeReprKind::InOut: case TypeReprKind::Metatype: case TypeReprKind::Owned: case TypeReprKind::Protocol: case TypeReprKind::Shared: case TypeReprKind::SILBox: return { }; case TypeReprKind::Fixed: llvm_unreachable("Cannot get fixed TypeReprs in name lookup"); case TypeReprKind::Optional: case TypeReprKind::ImplicitlyUnwrappedOptional: return { 1, ctx.getOptionalDecl() }; } llvm_unreachable("unhandled kind"); } static DirectlyReferencedTypeDecls directReferencesForType(Type type) { // If it's a typealias, return that. if (auto aliasType = dyn_cast(type.getPointer())) return { 1, aliasType->getDecl() }; // If there is a generic declaration, return it. if (auto genericDecl = type->getAnyGeneric()) return { 1, genericDecl }; if (type->isExistentialType()) { DirectlyReferencedTypeDecls result; const auto &layout = type->getExistentialLayout(); // Superclass. if (auto superclassType = layout.explicitSuperclass) { if (auto superclassDecl = superclassType->getAnyGeneric()) { result.push_back(superclassDecl); } } // Protocols. for (auto protocolTy : layout.getProtocols()) result.push_back(protocolTy->getDecl()); return result; } return { }; } DirectlyReferencedTypeDecls InheritedDeclsReferencedRequest::evaluate( Evaluator &evaluator, llvm::PointerUnion decl, unsigned index) const { // Prefer syntactic information when we have it. TypeLoc &typeLoc = getTypeLoc(decl, index); if (auto typeRepr = typeLoc.getTypeRepr()) { // Figure out the context in which name lookup will occur. DeclContext *dc; if (auto typeDecl = decl.dyn_cast()) dc = typeDecl->getInnermostDeclContext(); else dc = decl.get(); return directReferencesForTypeRepr(evaluator, dc->getASTContext(), typeRepr, dc); } // Fall back to semantic types. // FIXME: In the long run, we shouldn't need this. Non-syntactic results // should be cached. if (auto type = typeLoc.getType()) { return directReferencesForType(type); } return { }; } DirectlyReferencedTypeDecls UnderlyingTypeDeclsReferencedRequest::evaluate( Evaluator &evaluator, TypeAliasDecl *typealias) const { // Prefer syntactic information when we have it. if (auto typeRepr = typealias->getUnderlyingTypeLoc().getTypeRepr()) { return directReferencesForTypeRepr(evaluator, typealias->getASTContext(), typeRepr, typealias); } // Fall back to semantic types. // FIXME: In the long run, we shouldn't need this. Non-syntactic results // should be cached. if (auto type = typealias->getUnderlyingTypeLoc().getType()) { return directReferencesForType(type); } return { }; } /// Evaluate a superclass declaration request. llvm::Expected SuperclassDeclRequest::evaluate(Evaluator &evaluator, NominalTypeDecl *subject) const { auto &Ctx = subject->getASTContext(); for (unsigned i : indices(subject->getInherited())) { // Find the inherited declarations referenced at this position. auto inheritedTypes = evaluateOrDefault(evaluator, InheritedDeclsReferencedRequest{subject, i}, {}); // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; bool anyObject = false; auto inheritedNominalTypes = resolveTypeDeclsToNominal(evaluator, Ctx, inheritedTypes, modulesFound, anyObject); // Look for a class declaration. for (auto inheritedNominal : inheritedNominalTypes) { if (auto classDecl = dyn_cast(inheritedNominal)) return classDecl; } } // Protocols also support '... where Self : Superclass'. auto *proto = dyn_cast(subject); if (proto == nullptr) return nullptr; auto selfBounds = getSelfBoundsFromWhereClause(proto); for (auto inheritedNominal : selfBounds.decls) if (auto classDecl = dyn_cast(inheritedNominal)) return classDecl; return nullptr; } llvm::Expected ExtendedNominalRequest::evaluate(Evaluator &evaluator, ExtensionDecl *ext) const { DirectlyReferencedTypeDecls referenced; ASTContext &ctx = ext->getASTContext(); // Prefer syntactic information when we have it. TypeLoc &typeLoc = ext->getExtendedTypeLoc(); if (auto typeRepr = typeLoc.getTypeRepr()) { referenced = directReferencesForTypeRepr(evaluator, ctx, typeRepr, ext); } else if (auto type = typeLoc.getType()) { // Fall back to semantic types. // FIXME: In the long run, we shouldn't need this. Non-syntactic results // should be cached. referenced = directReferencesForType(type); } // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; bool anyObject = false; auto nominalTypes = resolveTypeDeclsToNominal(evaluator, ctx, referenced, modulesFound, anyObject); return nominalTypes.empty() ? nullptr : nominalTypes.front(); } void swift::getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, unsigned i, llvm::SmallVectorImpl> &result, bool &anyObject) { auto typeDecl = decl.dyn_cast(); auto extDecl = decl.dyn_cast(); ASTContext &ctx = typeDecl ? typeDecl->getASTContext() : extDecl->getASTContext(); // Find inherited declarations. auto referenced = evaluateOrDefault(ctx.evaluator, InheritedDeclsReferencedRequest{decl, i}, {}); // Resolve those type declarations to nominal type declarations. SmallVector modulesFound; auto nominalTypes = resolveTypeDeclsToNominal(ctx.evaluator, ctx, referenced, modulesFound, anyObject); // Dig out the source location // FIXME: This is a hack. We need cooperation from // InheritedDeclsReferencedRequest to make this work. SourceLoc loc; if (TypeRepr *typeRepr = typeDecl ? typeDecl->getInherited()[i].getTypeRepr() : extDecl->getInherited()[i].getTypeRepr()){ loc = typeRepr->getLoc(); } // Form the result. for (auto nominal : nominalTypes) { result.push_back({loc, nominal}); } } SmallVector, 4> swift::getDirectlyInheritedNominalTypeDecls( llvm::PointerUnion decl, bool &anyObject) { auto typeDecl = decl.dyn_cast(); auto extDecl = decl.dyn_cast(); // Gather results from all of the inherited types. unsigned numInherited = typeDecl ? typeDecl->getInherited().size() : extDecl->getInherited().size(); SmallVector, 4> result; for (unsigned i : range(numInherited)) { getDirectlyInheritedNominalTypeDecls(decl, i, result, anyObject); } auto *protoDecl = dyn_cast_or_null(typeDecl); if (protoDecl == nullptr) return result; // FIXME: Refactor SelfBoundsFromWhereClauseRequest to dig out // the source location. SourceLoc loc = SourceLoc(); auto selfBounds = getSelfBoundsFromWhereClause(decl); anyObject |= selfBounds.anyObject; for (auto inheritedNominal : selfBounds.decls) result.emplace_back(loc, inheritedNominal); return result; } void FindLocalVal::checkPattern(const Pattern *Pat, DeclVisibilityKind Reason) { switch (Pat->getKind()) { case PatternKind::Tuple: for (auto &field : cast(Pat)->getElements()) checkPattern(field.getPattern(), Reason); return; case PatternKind::Paren: case PatternKind::Typed: case PatternKind::Var: return checkPattern(Pat->getSemanticsProvidingPattern(), Reason); case PatternKind::Named: return checkValueDecl(cast(Pat)->getDecl(), Reason); case PatternKind::EnumElement: { auto *OP = cast(Pat); if (OP->hasSubPattern()) checkPattern(OP->getSubPattern(), Reason); return; } case PatternKind::OptionalSome: checkPattern(cast(Pat)->getSubPattern(), Reason); return; case PatternKind::Is: { auto *isPat = cast(Pat); if (isPat->hasSubPattern()) checkPattern(isPat->getSubPattern(), Reason); return; } // Handle non-vars. case PatternKind::Bool: case PatternKind::Expr: case PatternKind::Any: return; } } void FindLocalVal::checkParameterList(const ParameterList *params) { for (auto param : *params) { checkValueDecl(param, DeclVisibilityKind::FunctionParameter); } } void FindLocalVal::checkGenericParams(GenericParamList *Params) { if (!Params) return; for (auto P : *Params) checkValueDecl(P, DeclVisibilityKind::GenericParameter); } void FindLocalVal::checkSourceFile(const SourceFile &SF) { for (Decl *D : SF.Decls) if (auto *TLCD = dyn_cast(D)) visitBraceStmt(TLCD->getBody(), /*isTopLevel=*/true); } void FindLocalVal::checkStmtCondition(const StmtCondition &Cond) { SourceLoc start = SourceLoc(); for (auto entry : Cond) { if (start.isInvalid()) start = entry.getStartLoc(); if (auto *P = entry.getPatternOrNull()) { SourceRange previousConditionsToHere = SourceRange(start, entry.getEndLoc()); if (!isReferencePointInRange(previousConditionsToHere)) checkPattern(P, DeclVisibilityKind::LocalVariable); } } } void FindLocalVal::visitIfStmt(IfStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; if (!S->getElseStmt() || !isReferencePointInRange(S->getElseStmt()->getSourceRange())) { checkStmtCondition(S->getCond()); } visit(S->getThenStmt()); if (S->getElseStmt()) visit(S->getElseStmt()); } void FindLocalVal::visitGuardStmt(GuardStmt *S) { if (SM.isBeforeInBuffer(Loc, S->getStartLoc())) return; // Names in the guard aren't visible until after the body. if (!isReferencePointInRange(S->getBody()->getSourceRange())) checkStmtCondition(S->getCond()); visit(S->getBody()); } void FindLocalVal::visitWhileStmt(WhileStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; checkStmtCondition(S->getCond()); visit(S->getBody()); } void FindLocalVal::visitRepeatWhileStmt(RepeatWhileStmt *S) { visit(S->getBody()); } void FindLocalVal::visitDoStmt(DoStmt *S) { visit(S->getBody()); } void FindLocalVal::visitForEachStmt(ForEachStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; visit(S->getBody()); if (!isReferencePointInRange(S->getSequence()->getSourceRange())) checkPattern(S->getPattern(), DeclVisibilityKind::LocalVariable); } void FindLocalVal::visitBraceStmt(BraceStmt *S, bool isTopLevelCode) { if (isTopLevelCode) { if (SM.isBeforeInBuffer(Loc, S->getStartLoc())) return; } else { if (!isReferencePointInRange(S->getSourceRange())) return; } for (auto elem : S->getElements()) { if (auto *S = elem.dyn_cast()) visit(S); } for (auto elem : S->getElements()) { if (auto *D = elem.dyn_cast()) { if (auto *VD = dyn_cast(D)) checkValueDecl(VD, DeclVisibilityKind::LocalVariable); } } } void FindLocalVal::visitSwitchStmt(SwitchStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; for (CaseStmt *C : S->getCases()) { visit(C); } } void FindLocalVal::visitCaseStmt(CaseStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; // Pattern names aren't visible in the patterns themselves, // just in the body or in where guards. bool inPatterns = isReferencePointInRange(S->getLabelItemsRange()); auto items = S->getCaseLabelItems(); if (inPatterns) { for (const auto &CLI : items) { auto guard = CLI.getGuardExpr(); if (guard && isReferencePointInRange(guard->getSourceRange())) { checkPattern(CLI.getPattern(), DeclVisibilityKind::LocalVariable); break; } } } if (!inPatterns && !items.empty()) checkPattern(items[0].getPattern(), DeclVisibilityKind::LocalVariable); visit(S->getBody()); } void FindLocalVal::visitDoCatchStmt(DoCatchStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; visit(S->getBody()); visitCatchClauses(S->getCatches()); } void FindLocalVal::visitCatchClauses(ArrayRef clauses) { // TODO: some sort of binary search? for (auto clause : clauses) { visitCatchStmt(clause); } } void FindLocalVal::visitCatchStmt(CatchStmt *S) { if (!isReferencePointInRange(S->getSourceRange())) return; // Names in the pattern aren't visible until after the pattern. if (!isReferencePointInRange(S->getErrorPattern()->getSourceRange())) checkPattern(S->getErrorPattern(), DeclVisibilityKind::LocalVariable); visit(S->getBody()); }