| //===--- LookupVisibleDecls - Swift Name Lookup Routines ------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the lookupVisibleDecls interface for visiting named |
| // declarations. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "NameLookupImpl.h" |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/GenericSignature.h" |
| #include "swift/AST/GenericSignatureBuilder.h" |
| #include "swift/AST/Initializer.h" |
| #include "swift/AST/LazyResolver.h" |
| #include "swift/AST/NameLookup.h" |
| #include "swift/AST/ProtocolConformance.h" |
| #include "swift/Basic/SourceManager.h" |
| #include "swift/Basic/STLExtras.h" |
| #include "swift/Sema/IDETypeChecking.h" |
| #include "llvm/ADT/SetVector.h" |
| #include <set> |
| |
| using namespace swift; |
| |
| void VisibleDeclConsumer::anchor() {} |
| void VectorDeclConsumer::anchor() {} |
| void NamedDeclConsumer::anchor() {} |
| |
| namespace { |
| struct LookupState { |
| private: |
| /// If \c false, an unqualified lookup of all visible decls in a |
| /// DeclContext. |
| /// |
| /// If \c true, lookup of all visible members of a given object (possibly of |
| /// metatype type). |
| unsigned IsQualified : 1; |
| |
| /// Is this a qualified lookup on a metatype? |
| unsigned IsOnMetatype : 1; |
| |
| /// Did we recurse into a superclass? |
| unsigned IsOnSuperclass : 1; |
| |
| unsigned InheritsSuperclassInitializers : 1; |
| |
| /// Should instance members be included even if lookup is performed on a type? |
| unsigned IncludeInstanceMembers : 1; |
| |
| LookupState() |
| : IsQualified(0), IsOnMetatype(0), IsOnSuperclass(0), |
| InheritsSuperclassInitializers(0), IncludeInstanceMembers(0) {} |
| |
| public: |
| LookupState(const LookupState &) = default; |
| |
| static LookupState makeQualified() { |
| LookupState Result; |
| Result.IsQualified = 1; |
| return Result; |
| } |
| |
| static LookupState makeUnqualified() { |
| LookupState Result; |
| Result.IsQualified = 0; |
| return Result; |
| } |
| |
| bool isQualified() const { return IsQualified; } |
| bool isOnMetatype() const { return IsOnMetatype; } |
| bool isOnSuperclass() const { return IsOnSuperclass; } |
| bool isInheritsSuperclassInitializers() const { |
| return InheritsSuperclassInitializers; |
| } |
| bool isIncludingInstanceMembers() const { return IncludeInstanceMembers; } |
| |
| LookupState withOnMetatype() const { |
| auto Result = *this; |
| Result.IsOnMetatype = 1; |
| return Result; |
| } |
| |
| LookupState withOnSuperclass() const { |
| auto Result = *this; |
| Result.IsOnSuperclass = 1; |
| return Result; |
| } |
| |
| LookupState withInheritsSuperclassInitializers() const { |
| auto Result = *this; |
| Result.InheritsSuperclassInitializers = 1; |
| return Result; |
| } |
| |
| LookupState withoutInheritsSuperclassInitializers() const { |
| auto Result = *this; |
| Result.InheritsSuperclassInitializers = 0; |
| return Result; |
| } |
| |
| LookupState withIncludedInstanceMembers() const { |
| auto Result = *this; |
| Result.IncludeInstanceMembers = 1; |
| return Result; |
| } |
| }; |
| } // end anonymous namespace |
| |
| static bool areTypeDeclsVisibleInLookupMode(LookupState LS) { |
| // Nested type declarations can be accessed only with unqualified lookup or |
| // on metatypes. |
| return !LS.isQualified() || LS.isOnMetatype(); |
| } |
| |
| static bool isDeclVisibleInLookupMode(ValueDecl *Member, LookupState LS, |
| const DeclContext *FromContext, |
| LazyResolver *TypeResolver) { |
| // Accessors are never visible directly in the source language. |
| if (isa<AccessorDecl>(Member)) |
| return false; |
| |
| if (TypeResolver) { |
| TypeResolver->resolveDeclSignature(Member); |
| } |
| |
| // Check access when relevant. |
| if (!Member->getDeclContext()->isLocalContext() && |
| !isa<GenericTypeParamDecl>(Member) && !isa<ParamDecl>(Member) && |
| FromContext->getASTContext().LangOpts.EnableAccessControl) { |
| if (!Member->isAccessibleFrom(FromContext)) |
| return false; |
| } |
| |
| if (auto *FD = dyn_cast<FuncDecl>(Member)) { |
| // Cannot call static functions on non-metatypes. |
| if (!LS.isOnMetatype() && FD->isStatic()) |
| return false; |
| |
| // Otherwise, either call a function or curry it. |
| return true; |
| } |
| if (auto *VD = dyn_cast<VarDecl>(Member)) { |
| // Cannot use static properties on non-metatypes. |
| if (!(LS.isQualified() && LS.isOnMetatype()) && VD->isStatic()) |
| return false; |
| |
| // Cannot use instance properties on metatypes. |
| if (LS.isOnMetatype() && !VD->isStatic() && !LS.isIncludingInstanceMembers()) |
| return false; |
| |
| return true; |
| } |
| if (isa<EnumElementDecl>(Member)) { |
| // Cannot reference enum elements on non-metatypes. |
| if (!(LS.isQualified() && LS.isOnMetatype())) |
| return false; |
| } |
| if (auto CD = dyn_cast<ConstructorDecl>(Member)) { |
| // Constructors with stub implementations cannot be called in Swift. |
| if (CD->hasStubImplementation()) |
| return false; |
| if (LS.isQualified() && LS.isOnSuperclass()) { |
| // Cannot call initializers from a superclass, except for inherited |
| // convenience initializers. |
| return LS.isInheritsSuperclassInitializers() && CD->isInheritable(); |
| } |
| } |
| if (isa<TypeDecl>(Member)) |
| return areTypeDeclsVisibleInLookupMode(LS); |
| |
| return true; |
| } |
| |
| /// Lookup members in extensions of \p LookupType, using \p BaseType as the |
| /// underlying type when checking any constraints on the extensions. |
| static void doGlobalExtensionLookup(Type BaseType, |
| Type LookupType, |
| SmallVectorImpl<ValueDecl *> &FoundDecls, |
| const DeclContext *CurrDC, |
| LookupState LS, |
| DeclVisibilityKind Reason, |
| LazyResolver *TypeResolver) { |
| auto nominal = LookupType->getAnyNominal(); |
| |
| // Look in each extension of this type. |
| for (auto extension : nominal->getExtensions()) { |
| if (!isExtensionApplied(*const_cast<DeclContext*>(CurrDC), BaseType, |
| extension)) |
| continue; |
| |
| bool validatedExtension = false; |
| for (auto Member : extension->getMembers()) { |
| if (auto VD = dyn_cast<ValueDecl>(Member)) |
| if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver)) { |
| // Resolve the extension, if we haven't done so already. |
| if (!validatedExtension && TypeResolver) { |
| TypeResolver->resolveExtension(extension); |
| validatedExtension = true; |
| } |
| |
| FoundDecls.push_back(VD); |
| } |
| } |
| } |
| |
| // Handle shadowing. |
| removeShadowedDecls(FoundDecls, CurrDC->getParentModule()); |
| } |
| |
| /// \brief Enumerate immediate members of the type \c LookupType and its |
| /// extensions, as seen from the context \c CurrDC. |
| /// |
| /// Don't do lookup into superclasses or implemented protocols. Uses |
| /// \p BaseType as the underlying type when checking any constraints on the |
| /// extensions. |
| static void lookupTypeMembers(Type BaseType, Type LookupType, |
| VisibleDeclConsumer &Consumer, |
| const DeclContext *CurrDC, LookupState LS, |
| DeclVisibilityKind Reason, |
| LazyResolver *TypeResolver) { |
| NominalTypeDecl *D = LookupType->getAnyNominal(); |
| assert(D && "should have a nominal type"); |
| |
| bool LookupFromChildDeclContext = false; |
| const DeclContext *TempDC = CurrDC; |
| while (!TempDC->isModuleContext()) { |
| if (TempDC == D) { |
| LookupFromChildDeclContext = true; |
| break; |
| } |
| TempDC = TempDC->getParent(); |
| } |
| |
| SmallVector<ValueDecl*, 2> FoundDecls; |
| |
| if (LookupFromChildDeclContext) { |
| // Current decl context is contained inside 'D', so generic parameters |
| // are visible. |
| if (D->getGenericParams()) |
| for (auto Param : *D->getGenericParams()) |
| if (isDeclVisibleInLookupMode(Param, LS, CurrDC, TypeResolver)) |
| FoundDecls.push_back(Param); |
| } |
| |
| for (Decl *Member : D->getMembers()) { |
| if (auto *VD = dyn_cast<ValueDecl>(Member)) |
| if (isDeclVisibleInLookupMode(VD, LS, CurrDC, TypeResolver)) |
| FoundDecls.push_back(VD); |
| } |
| doGlobalExtensionLookup(BaseType, LookupType, FoundDecls, CurrDC, LS, Reason, |
| TypeResolver); |
| |
| // Report the declarations we found to the consumer. |
| for (auto *VD : FoundDecls) |
| Consumer.foundDecl(VD, Reason); |
| } |
| |
| /// Enumerate AnyObject declarations as seen from context \c CurrDC. |
| static void doDynamicLookup(VisibleDeclConsumer &Consumer, |
| const DeclContext *CurrDC, |
| LookupState LS, |
| LazyResolver *TypeResolver) { |
| class DynamicLookupConsumer : public VisibleDeclConsumer { |
| VisibleDeclConsumer &ChainedConsumer; |
| LookupState LS; |
| const DeclContext *CurrDC; |
| LazyResolver *TypeResolver; |
| llvm::DenseSet<std::pair<DeclBaseName, CanType>> FunctionsReported; |
| llvm::DenseSet<CanType> SubscriptsReported; |
| llvm::DenseSet<std::pair<Identifier, CanType>> PropertiesReported; |
| |
| public: |
| explicit DynamicLookupConsumer(VisibleDeclConsumer &ChainedConsumer, |
| LookupState LS, const DeclContext *CurrDC, |
| LazyResolver *TypeResolver) |
| : ChainedConsumer(ChainedConsumer), LS(LS), CurrDC(CurrDC), |
| TypeResolver(TypeResolver) {} |
| |
| void foundDecl(ValueDecl *D, DeclVisibilityKind Reason) override { |
| // 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 (D->getOverriddenDecl()) |
| return; |
| |
| // If the declaration is not @objc, it cannot be called dynamically. |
| if (!D->isObjC()) |
| return; |
| |
| // Ensure that the declaration has a type. |
| if (!D->hasInterfaceType()) { |
| if (!TypeResolver) return; |
| TypeResolver->resolveDeclSignature(D); |
| if (!D->hasInterfaceType()) return; |
| } |
| |
| switch (D->getKind()) { |
| #define DECL(ID, SUPER) \ |
| case DeclKind::ID: |
| #define VALUE_DECL(ID, SUPER) |
| #include "swift/AST/DeclNodes.def" |
| llvm_unreachable("not a ValueDecl!"); |
| |
| // Types cannot be found by dynamic lookup. |
| case DeclKind::GenericTypeParam: |
| case DeclKind::AssociatedType: |
| case DeclKind::TypeAlias: |
| case DeclKind::Enum: |
| case DeclKind::Class: |
| case DeclKind::Struct: |
| case DeclKind::Protocol: |
| return; |
| |
| // Initializers cannot be found by dynamic lookup. |
| case DeclKind::Constructor: |
| case DeclKind::Destructor: |
| return; |
| |
| // These cases are probably impossible here but can also just |
| // be safely ignored. |
| case DeclKind::EnumElement: |
| case DeclKind::Param: |
| case DeclKind::Module: |
| return; |
| |
| // For other kinds of values, check if we already reported a decl |
| // with the same signature. |
| |
| case DeclKind::Accessor: |
| case DeclKind::Func: { |
| auto FD = cast<FuncDecl>(D); |
| assert(FD->hasImplicitSelfDecl() && "should not find free functions"); |
| (void)FD; |
| |
| if (FD->isInvalid()) |
| break; |
| |
| // Get the type without the first uncurry level with 'self'. |
| CanType T = FD->getMethodInterfaceType()->getCanonicalType(); |
| |
| auto Signature = std::make_pair(D->getBaseName(), T); |
| if (!FunctionsReported.insert(Signature).second) |
| return; |
| break; |
| } |
| |
| case DeclKind::Subscript: { |
| auto Signature = D->getInterfaceType()->getCanonicalType(); |
| if (!SubscriptsReported.insert(Signature).second) |
| return; |
| break; |
| } |
| |
| case DeclKind::Var: { |
| auto *VD = cast<VarDecl>(D); |
| auto Signature = |
| std::make_pair(VD->getName(), |
| VD->getInterfaceType()->getCanonicalType()); |
| if (!PropertiesReported.insert(Signature).second) |
| return; |
| break; |
| } |
| } |
| |
| if (isDeclVisibleInLookupMode(D, LS, CurrDC, TypeResolver)) |
| ChainedConsumer.foundDecl(D, DeclVisibilityKind::DynamicLookup); |
| } |
| }; |
| |
| DynamicLookupConsumer ConsumerWrapper(Consumer, LS, CurrDC, TypeResolver); |
| |
| CurrDC->getParentSourceFile()->forAllVisibleModules( |
| [&](ModuleDecl::ImportedModule Import) { |
| Import.second->lookupClassMembers(Import.first, ConsumerWrapper); |
| }); |
| } |
| |
| namespace { |
| typedef llvm::SmallPtrSet<TypeDecl *, 8> VisitedSet; |
| } // end anonymous namespace |
| |
| static DeclVisibilityKind getReasonForSuper(DeclVisibilityKind Reason) { |
| switch (Reason) { |
| case DeclVisibilityKind::MemberOfCurrentNominal: |
| case DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal: |
| case DeclVisibilityKind::MemberOfSuper: |
| return DeclVisibilityKind::MemberOfSuper; |
| |
| case DeclVisibilityKind::MemberOfOutsideNominal: |
| return DeclVisibilityKind::MemberOfOutsideNominal; |
| |
| default: |
| llvm_unreachable("should not see this kind"); |
| } |
| } |
| |
| static void lookupDeclsFromProtocolsBeingConformedTo( |
| Type BaseTy, VisibleDeclConsumer &Consumer, LookupState LS, |
| const DeclContext *FromContext, DeclVisibilityKind Reason, |
| LazyResolver *TypeResolver, VisitedSet &Visited) { |
| NominalTypeDecl *CurrNominal = BaseTy->getAnyNominal(); |
| if (!CurrNominal) |
| return; |
| |
| for (auto Conformance : CurrNominal->getAllConformances()) { |
| auto Proto = Conformance->getProtocol(); |
| if (!Proto->isAccessibleFrom(FromContext)) |
| continue; |
| |
| DeclVisibilityKind ReasonForThisProtocol; |
| if (Reason == DeclVisibilityKind::MemberOfCurrentNominal) |
| ReasonForThisProtocol = |
| DeclVisibilityKind::MemberOfProtocolImplementedByCurrentNominal; |
| else |
| ReasonForThisProtocol = getReasonForSuper(Reason); |
| |
| auto NormalConformance = Conformance->getRootNormalConformance(); |
| for (auto Member : Proto->getMembers()) { |
| if (auto *ATD = dyn_cast<AssociatedTypeDecl>(Member)) { |
| // Skip type decls if they aren't visible, or any type that has a |
| // witness. This cuts down on duplicates. |
| if (areTypeDeclsVisibleInLookupMode(LS) && |
| !NormalConformance->hasTypeWitness(ATD)) { |
| Consumer.foundDecl(ATD, ReasonForThisProtocol); |
| } |
| continue; |
| } |
| if (auto *VD = dyn_cast<ValueDecl>(Member)) { |
| if (TypeResolver) { |
| TypeResolver->resolveDeclSignature(VD); |
| if (!NormalConformance->hasWitness(VD) && |
| (Conformance->getDeclContext()->getParentSourceFile() != |
| FromContext->getParentSourceFile())) |
| TypeResolver->resolveWitness(NormalConformance, VD); |
| } |
| // Skip value requirements that have corresponding witnesses. This cuts |
| // down on duplicates. |
| if (!NormalConformance->hasWitness(VD) || |
| !NormalConformance->getWitness(VD, nullptr) || |
| NormalConformance->getWitness(VD, nullptr).getDecl()->getFullName() |
| != VD->getFullName()) { |
| Consumer.foundDecl(VD, ReasonForThisProtocol); |
| } |
| } |
| } |
| |
| // Add members from any extensions. |
| SmallVector<ValueDecl *, 2> FoundDecls; |
| doGlobalExtensionLookup(BaseTy, Proto->getDeclaredType(), FoundDecls, |
| FromContext, LS, ReasonForThisProtocol, |
| TypeResolver); |
| for (auto *VD : FoundDecls) |
| Consumer.foundDecl(VD, ReasonForThisProtocol); |
| } |
| } |
| |
| static void |
| lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer, |
| const DeclContext *CurrDC, LookupState LS, |
| DeclVisibilityKind Reason, |
| LazyResolver *TypeResolver, |
| GenericSignatureBuilder *GSB, |
| VisitedSet &Visited); |
| |
| // Filters out restated declarations from a protocol hierarchy |
| // or equivalent requirements from protocol composition types. |
| class RestateFilteringConsumer : public VisibleDeclConsumer { |
| LazyResolver *resolver; |
| |
| using FoundDecl = std::pair<ValueDecl*, DeclVisibilityKind>; |
| using NameAndType = std::pair<DeclName, CanType>; |
| |
| llvm::DenseMap<DeclName, FoundDecl> foundVars; |
| llvm::DenseMap<NameAndType, FoundDecl> foundFuncs; |
| llvm::MapVector<ValueDecl*, DeclVisibilityKind> declsToReport; |
| |
| template <typename K> |
| void addDecl(llvm::DenseMap<K, FoundDecl> &Map, K Key, FoundDecl FD) { |
| // Add the declaration if we haven't found an equivalent yet, otherwise |
| // replace the equivalent if the found decl has a higher access level. |
| auto existingDecl = Map.find(Key); |
| |
| if ((existingDecl == Map.end()) || |
| (Map[Key].first->getFormalAccess() < FD.first->getFormalAccess())) { |
| if (existingDecl != Map.end()) |
| declsToReport.erase({existingDecl->getSecond().first}); |
| Map[Key] = FD; |
| declsToReport.insert(FD); |
| } |
| } |
| |
| CanType stripSelfRequirementsIfNeeded(ValueDecl *VD, |
| GenericFunctionType *GFT) const { |
| // Preserve the generic signature if this is a subscript, which are uncurried, |
| // or if we have generic params other than Self. Otherwise, use |
| // the resultType of the curried function type. |
| // When we keep the generic signature, we remove the requirements |
| // from Self to make sure they don't prevent us from recognizing restatements. |
| auto params = GFT->getGenericParams(); |
| if (params.size() == 1 && !isa<SubscriptDecl>(VD)) { |
| return GFT->getResult()->getCanonicalType(); |
| } |
| auto Self = VD->getDeclContext()->getSelfInterfaceType(); |
| SmallVector<Requirement, 4> newReqs; |
| for (auto req: GFT->getRequirements()) { |
| if (!Self->isEqual(req.getFirstType())) |
| newReqs.push_back(req); |
| } |
| auto newSig = GenericSignature::get(params, newReqs, false); |
| |
| return GenericFunctionType::get(newSig, GFT->getParams(), |
| GFT->getResult(), GFT->getExtInfo()) |
| ->getCanonicalType(); |
| } |
| |
| public: |
| RestateFilteringConsumer(Type baseTy, const DeclContext *DC, |
| LazyResolver *resolver) |
| : resolver(resolver) { |
| assert(DC && baseTy && !baseTy->hasLValueType()); |
| } |
| |
| void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { |
| assert(VD); |
| // If this isn't a protocol context, don't look further into the decl. |
| if (!isa<ProtocolDecl>(VD->getDeclContext())) { |
| declsToReport.insert({VD, Reason}); |
| return; |
| } |
| if (resolver) |
| resolver->resolveDeclSignature(VD); |
| |
| if (!VD->hasInterfaceType()) { |
| declsToReport.insert({VD, Reason}); |
| return; |
| } |
| if (auto GFT = VD->getInterfaceType()->getAs<GenericFunctionType>()) { |
| auto type = stripSelfRequirementsIfNeeded(VD, GFT); |
| addDecl(foundFuncs, {VD->getFullName(), type}, {VD, Reason}); |
| return; |
| } |
| addDecl(foundVars, VD->getFullName(), {VD, Reason}); |
| } |
| |
| void feedResultsToConsumer(VisibleDeclConsumer &Consumer) const { |
| for (const auto entry: declsToReport) |
| Consumer.foundDecl(entry.first, entry.second); |
| } |
| }; |
| |
| static void |
| lookupVisibleProtocolMemberDecls(Type BaseTy, ProtocolType *PT, |
| VisibleDeclConsumer &Consumer, |
| const DeclContext *CurrDC, LookupState LS, |
| DeclVisibilityKind Reason, |
| LazyResolver *TypeResolver, |
| GenericSignatureBuilder *GSB, |
| VisitedSet &Visited) { |
| if (!Visited.insert(PT->getDecl()).second) |
| return; |
| |
| for (auto Proto : PT->getDecl()->getInheritedProtocols()) |
| lookupVisibleProtocolMemberDecls(BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, |
| LS, getReasonForSuper(Reason), TypeResolver, |
| GSB, Visited); |
| lookupTypeMembers(BaseTy, PT, Consumer, CurrDC, LS, Reason, TypeResolver); |
| } |
| |
| static void lookupVisibleMemberDeclsImpl( |
| Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, |
| LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, |
| GenericSignatureBuilder *GSB, VisitedSet &Visited) { |
| // Just look through l-valueness. It doesn't affect name lookup. |
| assert(BaseTy && "lookup into null type"); |
| assert(!BaseTy->hasLValueType()); |
| |
| // Handle metatype references, as in "some_type.some_member". These are |
| // special and can't have extensions. |
| if (auto MTT = BaseTy->getAs<AnyMetatypeType>()) { |
| // The metatype represents an arbitrary named type: dig through to the |
| // declared type to see what we're dealing with. |
| Type Ty = MTT->getInstanceType(); |
| if (Ty->is<AnyMetatypeType>()) |
| return; |
| |
| LookupState subLS = LookupState::makeQualified().withOnMetatype(); |
| if (LS.isIncludingInstanceMembers()) { |
| subLS = subLS.withIncludedInstanceMembers(); |
| } |
| |
| // Just perform normal dot lookup on the type see if we find extensions or |
| // anything else. For example, type SomeTy.SomeMember can look up static |
| // functions, and can even look up non-static functions as well (thus |
| // getting the address of the member). |
| lookupVisibleMemberDeclsImpl(Ty, Consumer, CurrDC, subLS, Reason, |
| TypeResolver, GSB, Visited); |
| return; |
| } |
| |
| // Lookup module references, as on some_module.some_member. These are |
| // special and can't have extensions. |
| if (ModuleType *MT = BaseTy->getAs<ModuleType>()) { |
| AccessFilteringDeclConsumer FilteringConsumer(CurrDC, Consumer); |
| MT->getModule()->lookupVisibleDecls(ModuleDecl::AccessPathTy(), |
| FilteringConsumer, |
| NLKind::QualifiedLookup); |
| return; |
| } |
| |
| // If the base is AnyObject, we are doing dynamic lookup. |
| if (BaseTy->isAnyObject()) { |
| doDynamicLookup(Consumer, CurrDC, LS, TypeResolver); |
| return; |
| } |
| |
| // If the base is a protocol, enumerate its members. |
| if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) { |
| lookupVisibleProtocolMemberDecls(BaseTy, PT, Consumer, CurrDC, LS, Reason, |
| TypeResolver, GSB, Visited); |
| return; |
| } |
| |
| // If the base is a protocol composition, enumerate members of the protocols. |
| if (auto PC = BaseTy->getAs<ProtocolCompositionType>()) { |
| for (auto Member : PC->getMembers()) |
| lookupVisibleMemberDeclsImpl(Member, Consumer, CurrDC, LS, Reason, |
| TypeResolver, GSB, Visited); |
| return; |
| } |
| |
| // Enumerate members of archetype's requirements. |
| if (ArchetypeType *Archetype = BaseTy->getAs<ArchetypeType>()) { |
| for (auto Proto : Archetype->getConformsTo()) |
| lookupVisibleProtocolMemberDecls( |
| BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS, |
| getReasonForSuper(Reason), TypeResolver, GSB, Visited); |
| |
| if (auto superclass = Archetype->getSuperclass()) |
| lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS, |
| getReasonForSuper(Reason), TypeResolver, |
| GSB, Visited); |
| return; |
| } |
| |
| // If we're looking into a type parameter and we have a generic signature |
| // builder, use the GSB to resolve where we should look. |
| if (BaseTy->isTypeParameter() && GSB) { |
| auto EquivClass = |
| GSB->resolveEquivalenceClass(BaseTy, |
| ArchetypeResolutionKind::CompleteWellFormed); |
| if (!EquivClass) return; |
| |
| if (EquivClass->concreteType) { |
| BaseTy = EquivClass->concreteType; |
| } else { |
| // Conformances |
| for (const auto &Conforms : EquivClass->conformsTo) { |
| lookupVisibleProtocolMemberDecls( |
| BaseTy, Conforms.first->getDeclaredType(), Consumer, CurrDC, |
| LS, getReasonForSuper(Reason), TypeResolver, GSB, Visited); |
| } |
| |
| // Superclass. |
| if (EquivClass->superclass) { |
| lookupVisibleMemberDeclsImpl(EquivClass->superclass, Consumer, CurrDC, |
| LS, getReasonForSuper(Reason), |
| TypeResolver, GSB, Visited); |
| } |
| return; |
| } |
| } |
| |
| llvm::SmallPtrSet<ClassDecl *, 8> Ancestors; |
| do { |
| NominalTypeDecl *CurNominal = BaseTy->getAnyNominal(); |
| if (!CurNominal) |
| break; |
| |
| // Look in for members of a nominal type. |
| lookupTypeMembers(BaseTy, BaseTy, Consumer, CurrDC, LS, Reason, |
| TypeResolver); |
| lookupDeclsFromProtocolsBeingConformedTo(BaseTy, Consumer, LS, CurrDC, |
| Reason, TypeResolver, Visited); |
| // If we have a class type, look into its superclass. |
| auto *CurClass = dyn_cast<ClassDecl>(CurNominal); |
| |
| // FIXME: We check `getSuperclass()` here because we'll be using the |
| // superclass Type below, and in ill-formed code `hasSuperclass()` could |
| // be true while `getSuperclass()` returns null, because the latter |
| // looks for a declaration. |
| if (CurClass && CurClass->getSuperclass()) { |
| // FIXME: This path is no substitute for an actual circularity check. |
| // The real fix is to check that the superclass doesn't introduce a |
| // circular reference before it's written into the AST. |
| if (Ancestors.count(CurClass)) { |
| break; |
| } |
| |
| BaseTy = CurClass->getSuperclass(); |
| Reason = getReasonForSuper(Reason); |
| |
| bool InheritsSuperclassInitializers = |
| CurClass->inheritsSuperclassInitializers(TypeResolver); |
| if (LS.isOnSuperclass() && !InheritsSuperclassInitializers) |
| LS = LS.withoutInheritsSuperclassInitializers(); |
| else if (!LS.isOnSuperclass()) { |
| LS = LS.withOnSuperclass(); |
| if (InheritsSuperclassInitializers) |
| LS = LS.withInheritsSuperclassInitializers(); |
| } |
| } else { |
| break; |
| } |
| Ancestors.insert(CurClass); |
| } while (1); |
| } |
| |
| namespace { |
| |
| struct FoundDeclTy { |
| ValueDecl *D; |
| DeclVisibilityKind Reason; |
| |
| FoundDeclTy(ValueDecl *D, DeclVisibilityKind Reason) |
| : D(D), Reason(Reason) {} |
| |
| friend bool operator==(const FoundDeclTy &LHS, const FoundDeclTy &RHS) { |
| // If this ever changes - e.g. to include Reason - be sure to also update |
| // DenseMapInfo<FoundDeclTy>::getHashValue(). |
| return LHS.D == RHS.D; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| namespace llvm { |
| |
| template <> struct DenseMapInfo<FoundDeclTy> { |
| static inline FoundDeclTy getEmptyKey() { |
| return FoundDeclTy{nullptr, DeclVisibilityKind::LocalVariable}; |
| } |
| |
| static inline FoundDeclTy getTombstoneKey() { |
| return FoundDeclTy{reinterpret_cast<ValueDecl *>(0x1), |
| DeclVisibilityKind::LocalVariable}; |
| } |
| |
| static unsigned getHashValue(const FoundDeclTy &Val) { |
| // Note: FoundDeclTy::operator== only considers D, so don't hash Reason here. |
| return llvm::hash_value(Val.D); |
| } |
| |
| static bool isEqual(const FoundDeclTy &LHS, const FoundDeclTy &RHS) { |
| return LHS == RHS; |
| } |
| }; |
| |
| } // namespace llvm |
| |
| namespace { |
| |
| /// Hack to guess at whether substituting into the type of a declaration will |
| /// be okay. |
| /// FIXME: This is awful. We should either have Type::subst() work for |
| /// GenericFunctionType, or we should kill it outright. |
| static bool shouldSubstIntoDeclType(Type type) { |
| auto genericFnType = type->getAs<GenericFunctionType>(); |
| if (!genericFnType) return true; |
| |
| return false; |
| } |
| |
| class OverrideFilteringConsumer : public VisibleDeclConsumer { |
| public: |
| std::set<ValueDecl *> AllFoundDecls; |
| std::map<DeclBaseName, std::set<ValueDecl *>> FoundDecls; |
| llvm::SetVector<FoundDeclTy> DeclsToReport; |
| Type BaseTy; |
| const DeclContext *DC; |
| LazyResolver *TypeResolver; |
| bool IsTypeLookup = false; |
| |
| OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC, |
| LazyResolver *resolver) |
| : BaseTy(BaseTy), DC(DC), TypeResolver(resolver) { |
| assert(!BaseTy->hasLValueType()); |
| if (auto *MetaTy = BaseTy->getAs<AnyMetatypeType>()) { |
| BaseTy = MetaTy->getInstanceType(); |
| IsTypeLookup = true; |
| } |
| assert(DC && BaseTy); |
| } |
| |
| void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) override { |
| if (!AllFoundDecls.insert(VD).second) |
| return; |
| |
| // If this kind of declaration doesn't participate in overriding, there's |
| // no filtering to do here. |
| if (!isa<AbstractFunctionDecl>(VD) && !isa<AbstractStorageDecl>(VD)) { |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| return; |
| } |
| |
| if (TypeResolver) { |
| TypeResolver->resolveDeclSignature(VD); |
| } |
| |
| if (VD->isInvalid()) { |
| FoundDecls[VD->getBaseName()].insert(VD); |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| return; |
| } |
| auto &PossiblyConflicting = FoundDecls[VD->getBaseName()]; |
| |
| // Check all overridden decls. |
| { |
| auto *CurrentVD = VD->getOverriddenDecl(); |
| while (CurrentVD) { |
| if (!AllFoundDecls.insert(CurrentVD).second) |
| break; |
| if (PossiblyConflicting.count(CurrentVD)) { |
| PossiblyConflicting.erase(CurrentVD); |
| PossiblyConflicting.insert(VD); |
| |
| bool Erased = DeclsToReport.remove( |
| FoundDeclTy(CurrentVD, DeclVisibilityKind::LocalVariable)); |
| assert(Erased); |
| (void)Erased; |
| |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| return; |
| } |
| CurrentVD = CurrentVD->getOverriddenDecl(); |
| } |
| } |
| |
| // Does it make sense to substitute types? |
| |
| // If the base type is AnyObject, we might be doing a dynamic |
| // lookup, so the base type won't match the type of the member's |
| // context type. |
| // |
| // If the base type is not a nominal type, we can't substitute |
| // the member type. |
| // |
| // If the member is a free function and not a member of a type, |
| // don't substitute either. |
| bool shouldSubst = (!BaseTy->isAnyObject() && |
| !BaseTy->hasTypeVariable() && |
| BaseTy->getNominalOrBoundGenericNominal() && |
| VD->getDeclContext()->isTypeContext()); |
| ModuleDecl *M = DC->getParentModule(); |
| |
| // Hack; we shouldn't be filtering at this level anyway. |
| if (!VD->hasInterfaceType()) { |
| FoundDecls[VD->getBaseName()].insert(VD); |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| return; |
| } |
| |
| auto FoundSignature = VD->getOverloadSignature(); |
| auto FoundSignatureType = VD->getOverloadSignatureType(); |
| if (FoundSignatureType && shouldSubst && |
| shouldSubstIntoDeclType(FoundSignatureType)) { |
| auto subs = BaseTy->getMemberSubstitutionMap(M, VD); |
| if (auto CT = FoundSignatureType.subst(subs)) |
| FoundSignatureType = CT->getCanonicalType(); |
| } |
| |
| for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end(); |
| I != E; ++I) { |
| auto *OtherVD = *I; |
| if (OtherVD->isInvalid() || !OtherVD->hasInterfaceType()) { |
| // For some invalid decls it might be impossible to compute the |
| // signature, for example, if the types could not be resolved. |
| continue; |
| } |
| |
| auto OtherSignature = OtherVD->getOverloadSignature(); |
| auto OtherSignatureType = OtherVD->getOverloadSignatureType(); |
| if (OtherSignatureType && shouldSubst && |
| shouldSubstIntoDeclType(OtherSignatureType)) { |
| auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD); |
| if (auto CT = OtherSignatureType.subst(subs)) |
| OtherSignatureType = CT->getCanonicalType(); |
| } |
| |
| if (conflicting(M->getASTContext(), FoundSignature, FoundSignatureType, |
| OtherSignature, OtherSignatureType, |
| /*wouldConflictInSwift5*/nullptr, |
| /*skipProtocolExtensionCheck*/true)) { |
| if (VD->getFormalAccess() > OtherVD->getFormalAccess()) { |
| PossiblyConflicting.erase(I); |
| PossiblyConflicting.insert(VD); |
| |
| bool Erased = DeclsToReport.remove( |
| FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable)); |
| assert(Erased); |
| (void)Erased; |
| |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| } |
| return; |
| } |
| } |
| |
| PossiblyConflicting.insert(VD); |
| DeclsToReport.insert(FoundDeclTy(VD, Reason)); |
| } |
| }; |
| } // end anonymous namespace |
| |
| /// \brief Enumerate all members in \c BaseTy (including members of extensions, |
| /// superclasses and implemented protocols), as seen from the context \c CurrDC. |
| /// |
| /// This operation corresponds to a standard "dot" lookup operation like "a.b" |
| /// where 'self' is the type of 'a'. This operation is only valid after name |
| /// binding. |
| static void lookupVisibleMemberDecls( |
| Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC, |
| LookupState LS, DeclVisibilityKind Reason, LazyResolver *TypeResolver, |
| GenericSignatureBuilder *GSB) { |
| OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC, TypeResolver); |
| RestateFilteringConsumer restateConsumer(BaseTy, CurrDC, TypeResolver); |
| VisitedSet Visited; |
| lookupVisibleMemberDeclsImpl(BaseTy, restateConsumer, CurrDC, LS, Reason, |
| TypeResolver, GSB, Visited); |
| |
| // Report the declarations we found to the real consumer. |
| restateConsumer.feedResultsToConsumer(overrideConsumer); |
| for (const auto &DeclAndReason : overrideConsumer.DeclsToReport) |
| Consumer.foundDecl(DeclAndReason.D, DeclAndReason.Reason); |
| } |
| |
| static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer, |
| const DeclContext *DC, |
| LazyResolver *TypeResolver, |
| bool IncludeTopLevel, SourceLoc Loc) { |
| const ModuleDecl &M = *DC->getParentModule(); |
| const SourceManager &SM = DC->getASTContext().SourceMgr; |
| auto Reason = DeclVisibilityKind::MemberOfCurrentNominal; |
| |
| // 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. |
| while (!DC->isModuleScopeContext()) { |
| const ValueDecl *BaseDecl = nullptr; |
| Type ExtendedType; |
| auto LS = LookupState::makeUnqualified(); |
| |
| // Skip initializer contexts, we will not find any declarations there. |
| if (isa<Initializer>(DC)) { |
| DC = DC->getParent(); |
| LS = LS.withOnMetatype(); |
| } |
| |
| // We don't look for generic parameters if we are in the context of a |
| // nominal type: they will be looked up anyways via `lookupVisibleMemberDecls`. |
| if (DC && !isa<NominalTypeDecl>(DC)) { |
| if (auto *decl = DC->getAsDecl()) { |
| if (auto GC = decl->getAsGenericContext()) { |
| auto params = GC->getGenericParams(); |
| namelookup::FindLocalVal(SM, Loc, Consumer).checkGenericParams(params); |
| } |
| } |
| } |
| |
| if (auto *SE = dyn_cast<SubscriptDecl>(DC)) { |
| ExtendedType = SE->getDeclContext()->getSelfTypeInContext(); |
| DC = DC->getParent(); |
| BaseDecl = DC->getSelfNominalTypeDecl(); |
| } else if (auto *AFD = dyn_cast<AbstractFunctionDecl>(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()) { |
| namelookup::FindLocalVal(SM, Loc, Consumer).visit(AFD->getBody()); |
| } |
| |
| if (auto *P = AFD->getImplicitSelfDecl()) { |
| namelookup::FindLocalVal(SM, Loc, Consumer).checkValueDecl( |
| const_cast<ParamDecl *>(P), DeclVisibilityKind::FunctionParameter); |
| } |
| |
| namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList( |
| AFD->getParameters()); |
| |
| if (AFD->getDeclContext()->isTypeContext()) { |
| ExtendedType = AFD->getDeclContext()->getSelfTypeInContext(); |
| BaseDecl = AFD->getImplicitSelfDecl(); |
| DC = DC->getParent(); |
| |
| if (auto *FD = dyn_cast<FuncDecl>(AFD)) |
| if (FD->isStatic()) |
| ExtendedType = MetatypeType::get(ExtendedType); |
| } |
| } else if (auto CE = dyn_cast<ClosureExpr>(DC)) { |
| if (Loc.isValid()) { |
| namelookup::FindLocalVal(SM, Loc, Consumer).visit(CE->getBody()); |
| if (auto P = CE->getParameters()) { |
| namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P); |
| } |
| } |
| } else if (auto ED = dyn_cast<ExtensionDecl>(DC)) { |
| ExtendedType = ED->getSelfTypeInContext(); |
| if (ExtendedType) |
| BaseDecl = ExtendedType->getNominalOrBoundGenericNominal(); |
| } else if (auto ND = dyn_cast<NominalTypeDecl>(DC)) { |
| ExtendedType = ND->getSelfTypeInContext(); |
| BaseDecl = ND; |
| } |
| |
| if (BaseDecl && ExtendedType) |
| ::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, Reason, |
| TypeResolver, nullptr); |
| |
| DC = DC->getParent(); |
| Reason = DeclVisibilityKind::MemberOfOutsideNominal; |
| } |
| |
| SmallVector<ModuleDecl::ImportedModule, 8> extraImports; |
| if (auto SF = dyn_cast<SourceFile>(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(SM, Loc, Consumer).checkSourceFile(*SF); |
| } |
| |
| if (IncludeTopLevel) { |
| auto &cached = SF->getCachedVisibleDecls(); |
| if (!cached.empty()) { |
| for (auto result : cached) |
| Consumer.foundDecl(result, DeclVisibilityKind::VisibleAtTopLevel); |
| return; |
| } |
| |
| SF->getImportedModules(extraImports, ModuleDecl::ImportFilter::Private); |
| } |
| } |
| |
| if (IncludeTopLevel) { |
| using namespace namelookup; |
| SmallVector<ValueDecl *, 0> moduleResults; |
| auto &mutableM = const_cast<ModuleDecl&>(M); |
| lookupVisibleDeclsInModule(&mutableM, {}, moduleResults, |
| NLKind::UnqualifiedLookup, |
| ResolutionKind::Overloadable, |
| TypeResolver, DC, extraImports); |
| for (auto result : moduleResults) |
| Consumer.foundDecl(result, DeclVisibilityKind::VisibleAtTopLevel); |
| |
| if (auto SF = dyn_cast<SourceFile>(DC)) |
| SF->cacheVisibleDecls(std::move(moduleResults)); |
| } |
| } |
| |
| void swift::lookupVisibleDecls(VisibleDeclConsumer &Consumer, |
| const DeclContext *DC, |
| LazyResolver *TypeResolver, |
| bool IncludeTopLevel, |
| SourceLoc Loc) { |
| if (Loc.isInvalid()) { |
| lookupVisibleDeclsImpl(Consumer, DC, TypeResolver, IncludeTopLevel, Loc); |
| return; |
| } |
| |
| // Filtering out unusable values. |
| class LocalConsumer : public VisibleDeclConsumer { |
| const SourceManager &SM; |
| SourceLoc Loc; |
| VisibleDeclConsumer &Consumer; |
| |
| bool isUsableValue(ValueDecl *VD, DeclVisibilityKind Reason) { |
| |
| // Check "use within its own initial value" case. |
| if (auto *varD = dyn_cast<VarDecl>(VD)) |
| if (auto *PBD = varD->getParentPatternBinding()) |
| if (!PBD->isImplicit() && |
| SM.rangeContainsTokenLoc(PBD->getSourceRange(), Loc)) |
| return false; |
| |
| switch (Reason) { |
| case DeclVisibilityKind::LocalVariable: |
| // Use of 'TypeDecl's before declaration is allowed. |
| if (isa<TypeDecl>(VD)) |
| return true; |
| |
| return SM.isBeforeInBuffer(VD->getLoc(), Loc); |
| |
| case DeclVisibilityKind::VisibleAtTopLevel: |
| // TODO: Implement forward reference rule for script mode? Currently, |
| // it's not needed because the rest of the file hasn't been parsed. |
| // See: https://bugs.swift.org/browse/SR-284 for the rule. |
| return true; |
| |
| default: |
| // Other visibility kind are always usable. |
| return true; |
| } |
| } |
| |
| public: |
| LocalConsumer(const SourceManager &SM, SourceLoc Loc, |
| VisibleDeclConsumer &Consumer) |
| : SM(SM), Loc(Loc), Consumer(Consumer) {} |
| |
| void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason) { |
| if (isUsableValue(VD, Reason)) |
| Consumer.foundDecl(VD, Reason); |
| } |
| } LocalConsumer(DC->getASTContext().SourceMgr, Loc, Consumer); |
| |
| lookupVisibleDeclsImpl(LocalConsumer, DC, TypeResolver, IncludeTopLevel, Loc); |
| } |
| |
| void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy, |
| const DeclContext *CurrDC, |
| LazyResolver *TypeResolver, |
| bool includeInstanceMembers, |
| GenericSignatureBuilder *GSB) { |
| assert(CurrDC); |
| LookupState ls = LookupState::makeQualified(); |
| if (includeInstanceMembers) { |
| ls = ls.withIncludedInstanceMembers(); |
| } |
| |
| ::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls, |
| DeclVisibilityKind::MemberOfCurrentNominal, |
| TypeResolver, GSB); |
| } |