blob: 54ad443d91441a9d5e2d324a288d37306a3e5ce7 [file] [log] [blame]
//===--- 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/GenericSignatureBuilder.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/SubstitutionMap.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;
}
};
} // unnamed 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) {
if (TypeResolver) {
TypeResolver->resolveDeclSignature(Member);
TypeResolver->resolveAccessControl(Member);
}
// Check access when relevant.
if (!Member->getDeclContext()->isLocalContext() &&
!isa<GenericTypeParamDecl>(Member) && !isa<ParamDecl>(Member) &&
FromContext->getASTContext().LangOpts.EnableAccessControl) {
if (Member->isInvalid() && !Member->hasAccess())
return false;
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;
if (TypeResolver && extension->getAsProtocolExtensionContext()) {
if (!TypeResolver->isProtocolExtensionUsable(
const_cast<DeclContext *>(CurrDC), BaseType, extension)) {
continue;
}
validatedExtension = true;
}
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(), TypeResolver);
}
/// \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;
// 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::Func: {
auto FD = cast<FuncDecl>(D);
assert(FD->getImplicitSelfDecl() && "should not find free functions");
(void)FD;
if (FD->isInvalid())
break;
// Get the type without the first uncurry level with 'self'.
CanType T = D->getInterfaceType()
->castTo<AnyFunctionType>()
->getResult()
->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);
// 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);
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();
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,
TypeResolver);
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);
if (CurClass && CurClass->hasSuperclass()) {
// 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 {
/// Similar to swift::conflicting, but lenient about protocol extensions which
/// don't affect code completion's concept of overloading.
static bool relaxedConflicting(const OverloadSignature &sig1,
const OverloadSignature &sig2) {
// If the base names are different, they can't conflict.
if (sig1.Name.getBaseName() != sig2.Name.getBaseName())
return false;
// If one is a compound name and the other is not, they do not conflict
// if one is a property and the other is a non-nullary function.
if (sig1.Name.isCompoundName() != sig2.Name.isCompoundName()) {
return !((sig1.IsProperty && sig2.Name.getArgumentNames().size() > 0) ||
(sig2.IsProperty && sig1.Name.getArgumentNames().size() > 0));
}
// Allow null property types to match non-null ones, which only happens when
// one property is from a generic extension and the other is not.
if (sig1.InterfaceType != sig2.InterfaceType) {
if (!sig1.IsProperty || !sig2.IsProperty)
return false;
if (sig1.InterfaceType && sig2.InterfaceType)
return false;
}
return sig1.Name == sig2.Name && sig1.UnaryOperator == sig2.UnaryOperator &&
sig1.IsInstanceMember == sig2.IsInstanceMember;
}
/// 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;
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();
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);
TypeResolver->resolveAccessControl(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?
// Don't pass UnboundGenericType here. If you see this assertion
// being hit, fix the caller, don't remove it.
assert(!BaseTy->hasUnboundGenericType());
// 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();
if (FoundSignature.InterfaceType && shouldSubst &&
shouldSubstIntoDeclType(FoundSignature.InterfaceType)) {
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
if (auto CT = FoundSignature.InterfaceType.subst(subs))
FoundSignature.InterfaceType = 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();
if (OtherSignature.InterfaceType && shouldSubst &&
shouldSubstIntoDeclType(OtherSignature.InterfaceType)) {
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
if (auto CT = OtherSignature.InterfaceType.subst(subs))
OtherSignature.InterfaceType = CT->getCanonicalType();
}
if (relaxedConflicting(FoundSignature, OtherSignature)) {
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));
}
};
} // unnamed 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 ConsumerWrapper(BaseTy, CurrDC, TypeResolver);
VisitedSet Visited;
lookupVisibleMemberDeclsImpl(BaseTy, ConsumerWrapper, CurrDC, LS, Reason,
TypeResolver, GSB, Visited);
// Report the declarations we found to the real consumer.
for (const auto &DeclAndReason : ConsumerWrapper.DeclsToReport)
Consumer.foundDecl(DeclAndReason.D, DeclAndReason.Reason);
}
void swift::lookupVisibleDecls(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();
}
GenericParamList *GenericParams = DC->getGenericParamsOfContext();
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());
}
for (auto *P : AFD->getParameterLists())
namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(P);
// Constructors and destructors don't have 'self' in parameter patterns.
if (isa<ConstructorDecl>(AFD) || isa<DestructorDecl>(AFD))
if (auto *selfParam = AFD->getImplicitSelfDecl())
Consumer.foundDecl(const_cast<ParamDecl*>(selfParam),
DeclVisibilityKind::FunctionParameter);
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->getExtendedType();
if (ExtendedType)
BaseDecl = ExtendedType->getNominalOrBoundGenericNominal();
} else if (auto ND = dyn_cast<NominalTypeDecl>(DC)) {
ExtendedType = ND->getDeclaredTypeInContext();
BaseDecl = ND;
}
if (BaseDecl && ExtendedType) {
::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, Reason,
TypeResolver, nullptr);
}
// Check any generic parameters for something with the given name.
namelookup::FindLocalVal(SM, Loc, Consumer)
.checkGenericParams(GenericParams);
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::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);
}