blob: a1c1f733d5f7d8005d045a990afd938403faf1e9 [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 "TypeChecker.h"
#include "clang/AST/DeclObjC.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/GenericSignatureBuilder.h"
#include "swift/AST/ImportCache.h"
#include "swift/AST/Initializer.h"
#include "swift/AST/LazyResolver.h"
#include "swift/AST/ModuleNameLookup.h"
#include "swift/AST/NameLookup.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/PropertyWrappers.h"
#include "swift/AST/SourceFile.h"
#include "swift/Basic/SourceManager.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Sema/IDETypeCheckingRequests.h"
#include "swift/Sema/IDETypeChecking.h"
#include "llvm/ADT/SetVector.h"
#include <set>
using namespace swift;
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;
/// Should derived protocol requirements be included?
/// This option is only for override completion lookup.
unsigned IncludeDerivedRequirements : 1;
/// Should protocol extension members be included?
unsigned IncludeProtocolExtensionMembers : 1;
LookupState()
: IsQualified(0), IsOnMetatype(0), IsOnSuperclass(0),
InheritsSuperclassInitializers(0), IncludeInstanceMembers(0),
IncludeDerivedRequirements(0), IncludeProtocolExtensionMembers(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; }
bool isIncludingDerivedRequirements() const {
return IncludeDerivedRequirements;
}
bool isIncludingProtocolExtensionMembers() const {
return IncludeProtocolExtensionMembers;
}
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;
}
LookupState withIncludedDerivedRequirements() const {
auto Result = *this;
Result.IncludeDerivedRequirements = 1;
return Result;
}
LookupState withIncludeProtocolExtensionMembers() const {
auto Result = *this;
Result.IncludeProtocolExtensionMembers = 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) {
// Accessors are never visible directly in the source language.
if (isa<AccessorDecl>(Member))
return false;
// Check access when relevant.
if (!Member->getDeclContext()->isLocalContext() &&
!isa<GenericTypeParamDecl>(Member) && !isa<ParamDecl>(Member)) {
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 *SD = dyn_cast<SubscriptDecl>(Member)) {
// Cannot use static subscripts on non-metatypes.
if (!LS.isOnMetatype() && SD->isStatic())
return false;
// Cannot use instance subscript on metatypes.
if (LS.isOnMetatype() && !SD->isStatic() && !LS.isIncludingInstanceMembers())
return false;
return true;
}
if (auto *VD = dyn_cast<VarDecl>(Member)) {
// Cannot use static properties on non-metatypes.
if (!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.isOnMetatype())
return false;
}
if (auto CD = dyn_cast<ConstructorDecl>(Member)) {
if (!LS.isQualified())
return false;
// Constructors with stub implementations cannot be called in Swift.
if (CD->hasStubImplementation())
return false;
if (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;
}
/// Collect visble members from \p Parent into \p FoundDecls .
static void collectVisibleMemberDecls(const DeclContext *CurrDC, LookupState LS,
Type BaseType,
IterableDeclContext *Parent,
SmallVectorImpl<ValueDecl *> &FoundDecls) {
for (auto Member : Parent->getMembers()) {
auto *VD = dyn_cast<ValueDecl>(Member);
if (!VD)
continue;
if (!isDeclVisibleInLookupMode(VD, LS, CurrDC))
continue;
if (!evaluateOrDefault(CurrDC->getASTContext().evaluator,
IsDeclApplicableRequest(DeclApplicabilityOwner(CurrDC, BaseType, VD)),
false))
continue;
FoundDecls.push_back(VD);
}
}
static void
synthesizePropertyWrapperVariables(IterableDeclContext *IDC);
/// 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) {
auto nominal = LookupType->getAnyNominal();
// Look in each extension of this type.
for (auto extension : nominal->getExtensions()) {
if (!evaluateOrDefault(CurrDC->getASTContext().evaluator,
IsDeclApplicableRequest(DeclApplicabilityOwner(CurrDC, BaseType,
extension)), false))
continue;
synthesizePropertyWrapperVariables(extension);
collectVisibleMemberDecls(CurrDC, LS, BaseType, extension, FoundDecls);
}
// Handle shadowing.
removeShadowedDecls(FoundDecls, CurrDC);
}
/// 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) {
NominalTypeDecl *D = LookupType->getAnyNominal();
assert(D && "should have a nominal type");
SmallVector<ValueDecl*, 2> FoundDecls;
collectVisibleMemberDecls(CurrDC, LS, BaseType, D, FoundDecls);
doGlobalExtensionLookup(BaseType, LookupType, FoundDecls, CurrDC, LS, Reason);
// 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) {
class DynamicLookupConsumer : public VisibleDeclConsumer {
VisibleDeclConsumer &ChainedConsumer;
LookupState LS;
const DeclContext *CurrDC;
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)
: ChainedConsumer(ChainedConsumer), LS(LS), CurrDC(CurrDC) {}
void foundDecl(ValueDecl *D, DeclVisibilityKind Reason,
DynamicLookupInfo) 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;
// If the declaration is objc_direct, it cannot be called dynamically.
if (auto clangDecl = D->getClangDecl()) {
if (auto objCMethod = dyn_cast<clang::ObjCMethodDecl>(clangDecl)) {
if (objCMethod->isDirectMethod())
return;
} else if (auto objCProperty = dyn_cast<clang::ObjCPropertyDecl>(clangDecl)) {
if (objCProperty->isDirectProperty())
return;
}
}
if (D->isRecursiveValidation())
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:
case DeclKind::OpaqueType:
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::Param:
case DeclKind::Module:
case DeclKind::EnumElement:
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))
ChainedConsumer.foundDecl(D, DeclVisibilityKind::DynamicLookup,
DynamicLookupInfo::AnyObject);
}
};
DynamicLookupConsumer ConsumerWrapper(Consumer, LS, CurrDC);
for (auto Import : namelookup::getAllImports(CurrDC)) {
Import.importedModule->lookupClassMembers(Import.accessPath,
ConsumerWrapper);
}
}
namespace {
typedef llvm::SmallPtrSet<TypeDecl *, 8> VisitedSet;
} // end anonymous namespace
static DeclVisibilityKind getReasonForSuper(DeclVisibilityKind Reason) {
switch (Reason) {
case DeclVisibilityKind::MemberOfCurrentNominal:
case DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal:
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,
VisitedSet &Visited) {
NominalTypeDecl *CurrNominal = BaseTy->getAnyNominal();
if (!CurrNominal)
return;
ModuleDecl *Module = FromContext->getParentModule();
for (auto Conformance : CurrNominal->getAllConformances()) {
auto Proto = Conformance->getProtocol();
if (!Proto->isAccessibleFrom(FromContext))
continue;
// Skip unsatisfied conditional conformances.
// We can't check them if this type has an UnboundGenericType or if they
// couldn't be computed, so assume they conform in such cases.
if (!BaseTy->hasUnboundGenericType()) {
if (auto res = Conformance->getConditionalRequirementsIfAvailable()) {
if (!res->empty() && !Module->conformsToProtocol(BaseTy, Proto))
continue;
}
}
DeclVisibilityKind ReasonForThisProtocol;
if (Conformance->getKind() == ProtocolConformanceKind::Inherited)
ReasonForThisProtocol = getReasonForSuper(Reason);
else if (Reason == DeclVisibilityKind::MemberOfCurrentNominal)
ReasonForThisProtocol =
DeclVisibilityKind::MemberOfProtocolConformedToByCurrentNominal;
else
ReasonForThisProtocol = getReasonForSuper(Reason);
if (auto NormalConformance = dyn_cast<NormalProtocolConformance>(
Conformance->getRootConformance())) {
for (auto Member : Proto->getMembers()) {
// Skip associated types and value requirements that aren't visible
// or have a corresponding witness.
if (auto *ATD = dyn_cast<AssociatedTypeDecl>(Member)) {
if (areTypeDeclsVisibleInLookupMode(LS) &&
!Conformance->hasTypeWitness(ATD)) {
Consumer.foundDecl(ATD, ReasonForThisProtocol);
}
} else if (auto *VD = dyn_cast<ValueDecl>(Member)) {
if (!isDeclVisibleInLookupMode(VD, LS, FromContext))
continue;
if (!VD->isProtocolRequirement())
continue;
// Whether the given witness corresponds to a derived requirement.
const auto isDerivedRequirement = [Proto](const ValueDecl *Witness) {
return Witness->isImplicit() &&
Proto->getKnownDerivableProtocolKind();
};
DeclVisibilityKind ReasonForThisDecl = ReasonForThisProtocol;
if (const auto Witness = NormalConformance->getWitness(VD)) {
auto *WD = Witness.getDecl();
if (WD->getName() == VD->getName()) {
if (LS.isIncludingDerivedRequirements() &&
Reason == DeclVisibilityKind::MemberOfCurrentNominal &&
isDerivedRequirement(WD)) {
ReasonForThisDecl =
DeclVisibilityKind::MemberOfProtocolDerivedByCurrentNominal;
} else if (!LS.isIncludingProtocolExtensionMembers() &&
WD->getDeclContext()->getExtendedProtocolDecl()) {
// Don't skip this requiement.
// Witnesses in protocol extensions aren't reported.
} else {
// lookupVisibleMemberDecls() generally prefers witness members
// over requirements.
continue;
}
}
}
Consumer.foundDecl(VD, ReasonForThisDecl);
}
}
}
// Add members from any extensions.
if (LS.isIncludingProtocolExtensionMembers()) {
SmallVector<ValueDecl *, 2> FoundDecls;
doGlobalExtensionLookup(BaseTy, Proto->getDeclaredInterfaceType(),
FoundDecls, FromContext, LS,
ReasonForThisProtocol);
for (auto *VD : FoundDecls)
Consumer.foundDecl(VD, ReasonForThisProtocol);
}
}
}
static void
lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC, LookupState LS,
DeclVisibilityKind Reason,
GenericSignatureBuilder *GSB,
VisitedSet &Visited);
static void
lookupVisibleProtocolMemberDecls(Type BaseTy, ProtocolDecl *PD,
VisibleDeclConsumer &Consumer,
const DeclContext *CurrDC, LookupState LS,
DeclVisibilityKind Reason,
GenericSignatureBuilder *GSB,
VisitedSet &Visited) {
if (!Visited.insert(PD).second)
return;
for (auto Proto : PD->getInheritedProtocols())
lookupVisibleProtocolMemberDecls(BaseTy, Proto,
Consumer, CurrDC, LS,
getReasonForSuper(Reason),
GSB, Visited);
lookupTypeMembers(BaseTy, PD->getDeclaredInterfaceType(),
Consumer, CurrDC, LS, Reason);
}
// Generate '$' and '_' prefixed variables for members that have attached property
// wrappers.
static void
synthesizePropertyWrapperVariables(IterableDeclContext *IDC) {
auto SF = IDC->getAsGenericContext()->getParentSourceFile();
if (!SF || SF->Kind == SourceFileKind::Interface)
return;
for (auto Member : IDC->getMembers())
if (auto var = dyn_cast<VarDecl>(Member))
if (var->hasAttachedPropertyWrapper())
(void)var->getPropertyWrapperBackingPropertyInfo();
}
/// Trigger synthesizing implicit member declarations to make them "visible".
static void synthesizeMemberDeclsForLookup(NominalTypeDecl *NTD,
const DeclContext *DC) {
// Synthesize the memberwise initializer for structs or default initializer
// for classes.
if (!NTD->getASTContext().evaluator.hasActiveRequest(
SynthesizeMemberwiseInitRequest{NTD}))
TypeChecker::addImplicitConstructors(NTD);
// Check all conformances to trigger the synthesized decl generation.
// e.g. init(rawValue:) for RawRepresentable.
for (auto Conformance : NTD->getAllConformances()) {
auto Proto = Conformance->getProtocol();
if (!Proto->isAccessibleFrom(DC))
continue;
auto NormalConformance = dyn_cast<NormalProtocolConformance>(
Conformance->getRootConformance());
if (!NormalConformance)
continue;
NormalConformance->forEachTypeWitness(
[](AssociatedTypeDecl *, Type, TypeDecl *) { return false; },
/*useResolver=*/true);
NormalConformance->forEachValueWitness([](ValueDecl *, Witness) {},
/*useResolver=*/true);
}
synthesizePropertyWrapperVariables(NTD);
}
static void lookupVisibleMemberDeclsImpl(
Type BaseTy, VisibleDeclConsumer &Consumer, const DeclContext *CurrDC,
LookupState LS, DeclVisibilityKind Reason, 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 (auto dynSelfTy = Ty->getAs<DynamicSelfType>())
Ty = dynSelfTy->getSelfType();
if (Ty->is<AnyMetatypeType>())
return;
LookupState subLS = LookupState::makeQualified().withOnMetatype();
if (LS.isIncludingInstanceMembers()) {
subLS = subLS.withIncludedInstanceMembers();
}
if (LS.isIncludingDerivedRequirements()) {
subLS = subLS.withIncludedDerivedRequirements();
}
if (LS.isIncludingProtocolExtensionMembers()) {
subLS = subLS.withIncludeProtocolExtensionMembers();
}
// 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,
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(ImportPath::Access(),
FilteringConsumer,
NLKind::QualifiedLookup);
return;
}
// If the base is AnyObject, we are doing dynamic lookup.
if (BaseTy->isAnyObject()) {
doDynamicLookup(Consumer, CurrDC, LS);
return;
}
// If the base is a protocol, enumerate its members.
if (ProtocolType *PT = BaseTy->getAs<ProtocolType>()) {
lookupVisibleProtocolMemberDecls(BaseTy, PT->getDecl(),
Consumer, CurrDC, LS, Reason,
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,
GSB, Visited);
return;
}
// Enumerate members of archetype's requirements.
if (ArchetypeType *Archetype = BaseTy->getAs<ArchetypeType>()) {
for (auto Proto : Archetype->getConformsTo())
lookupVisibleProtocolMemberDecls(
BaseTy, Proto, Consumer, CurrDC, LS,
Reason, GSB, Visited);
if (auto superclass = Archetype->getSuperclass())
lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS,
Reason, 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, Consumer, CurrDC,
LS, getReasonForSuper(Reason), GSB, Visited);
}
// Superclass.
if (EquivClass->superclass) {
lookupVisibleMemberDeclsImpl(EquivClass->superclass, Consumer, CurrDC,
LS, getReasonForSuper(Reason),
GSB, Visited);
}
return;
}
}
auto lookupTy = BaseTy;
const auto synthesizeAndLookupTypeMembers = [&](NominalTypeDecl *NTD) {
synthesizeMemberDeclsForLookup(NTD, CurrDC);
// Look in for members of a nominal type.
lookupTypeMembers(BaseTy, lookupTy, Consumer, CurrDC, LS, Reason);
};
llvm::SmallPtrSet<ClassDecl *, 8> Ancestors;
{
const auto NTD = BaseTy->getAnyNominal();
if (NTD == nullptr)
return;
synthesizeAndLookupTypeMembers(NTD);
// Look into protocols only on the current nominal to avoid repeatedly
// visiting inherited conformances.
lookupDeclsFromProtocolsBeingConformedTo(BaseTy, Consumer, LS, CurrDC,
Reason, Visited);
const auto CD = dyn_cast<ClassDecl>(NTD);
// 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 (!CD || !CD->getSuperclass())
return;
// We have a superclass; switch state and look into the inheritance chain.
Ancestors.insert(CD);
Reason = getReasonForSuper(Reason);
lookupTy = CD->getSuperclass();
LS = LS.withOnSuperclass();
if (CD->inheritsSuperclassInitializers())
LS = LS.withInheritsSuperclassInitializers();
}
// Look into the inheritance chain.
do {
const auto CurClass = lookupTy->getClassOrBoundGenericClass();
// 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.insert(CurClass).second)
break;
synthesizeAndLookupTypeMembers(CurClass);
lookupTy = CurClass->getSuperclass();
if (!CurClass->inheritsSuperclassInitializers())
LS = LS.withoutInheritsSuperclassInitializers();
} while (lookupTy);
}
swift::DynamicLookupInfo::DynamicLookupInfo(
SubscriptDecl *subscript, Type baseType,
DeclVisibilityKind originalVisibility)
: kind(KeyPathDynamicMember) {
keypath.subscript = subscript;
keypath.baseType = baseType;
keypath.originalVisibility = originalVisibility;
}
const DynamicLookupInfo::KeyPathDynamicMemberInfo &
swift::DynamicLookupInfo::getKeyPathDynamicMember() const {
assert(kind == KeyPathDynamicMember);
return keypath;
}
namespace {
struct FoundDeclTy {
ValueDecl *D;
DeclVisibilityKind Reason;
DynamicLookupInfo dynamicLookupInfo;
FoundDeclTy(ValueDecl *D, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo)
: D(D), Reason(Reason), dynamicLookupInfo(dynamicLookupInfo) {}
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
// If a class 'Base' conforms to 'Proto', and my base type is a subclass
// 'Derived' of 'Base', use 'Base' not 'Derived' as the 'Self' type in the
// substitution map.
static Type getBaseTypeForMember(ModuleDecl *M, const ValueDecl *OtherVD,
Type BaseTy) {
if (auto *Proto = OtherVD->getDeclContext()->getSelfProtocolDecl()) {
if (BaseTy->getClassOrBoundGenericClass()) {
if (auto Conformance = M->lookupConformance(BaseTy, Proto)) {
auto *Superclass = Conformance.getConcrete()
->getRootConformance()
->getType()
->getClassOrBoundGenericClass();
return BaseTy->getSuperclassForDecl(Superclass);
}
}
}
return BaseTy;
}
namespace {
class OverrideFilteringConsumer : public VisibleDeclConsumer {
public:
llvm::SetVector<FoundDeclTy> Results;
llvm::SmallVector<ValueDecl *, 8> Decls;
llvm::SetVector<FoundDeclTy> FilteredResults;
llvm::DenseMap<DeclBaseName, llvm::SmallVector<ValueDecl *, 2>> DeclsByName;
Type BaseTy;
const DeclContext *DC;
OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC)
: BaseTy(BaseTy->getMetatypeInstanceType()),
DC(DC) {
assert(!BaseTy->hasLValueType());
assert(DC && BaseTy);
}
void foundDecl(ValueDecl *VD, DeclVisibilityKind Reason,
DynamicLookupInfo dynamicLookupInfo) override {
// SWIFT_ENABLE_TENSORFLOW
// Suppress "sequenced" as a result, because it crashes completions.
// TODO(TF-315): Fix properly and then remove this.
if (isa<FuncDecl>(VD) &&
cast<FuncDecl>(VD)->getBaseIdentifier().str() == "sequenced")
return;
if (!Results.insert({VD, Reason, dynamicLookupInfo}))
return;
DeclsByName[VD->getBaseName()] = {};
Decls.push_back(VD);
}
void filterDecls(VisibleDeclConsumer &Consumer) {
removeOverriddenDecls(Decls);
removeShadowedDecls(Decls, DC);
size_t index = 0;
for (const auto &DeclAndReason : Results) {
if (index >= Decls.size())
break;
if (DeclAndReason.D != Decls[index])
continue;
++index;
auto *const VD = DeclAndReason.D;
const auto Reason = DeclAndReason.Reason;
// If this kind of declaration doesn't participate in overriding, there's
// no filtering to do here.
if (!isa<AbstractFunctionDecl>(VD) &&
!isa<AbstractStorageDecl>(VD) &&
!isa<AssociatedTypeDecl>(VD)) {
FilteredResults.insert(DeclAndReason);
continue;
}
if (VD->isRecursiveValidation())
continue;
auto &PossiblyConflicting = DeclsByName[VD->getBaseName()];
if (VD->isInvalid()) {
FilteredResults.insert(DeclAndReason);
PossiblyConflicting.push_back(VD);
continue;
}
// 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 = (Reason != DeclVisibilityKind::DynamicLookup &&
!BaseTy->isAnyObject() && !BaseTy->hasTypeVariable() &&
!BaseTy->hasUnboundGenericType() &&
(BaseTy->getNominalOrBoundGenericNominal() ||
BaseTy->is<ArchetypeType>()) &&
VD->getDeclContext()->isTypeContext());
ModuleDecl *M = DC->getParentModule();
auto FoundSignature = VD->getOverloadSignature();
auto FoundSignatureType = VD->getOverloadSignatureType();
if (FoundSignatureType && shouldSubst) {
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
auto CT = FoundSignatureType.subst(subs);
if (!CT->hasError())
FoundSignatureType = CT->getCanonicalType();
}
bool FoundConflicting = false;
for (auto I = PossiblyConflicting.begin(), E = PossiblyConflicting.end();
I != E; ++I) {
auto *const OtherVD = *I;
if (OtherVD->isRecursiveValidation())
continue;
if (OtherVD->isInvalid())
continue;
auto OtherSignature = OtherVD->getOverloadSignature();
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
if (OtherSignatureType && shouldSubst) {
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
auto subs = ActualBaseTy->getMemberSubstitutionMap(M, OtherVD);
auto CT = OtherSignatureType.subst(subs);
if (!CT->hasError())
OtherSignatureType = CT->getCanonicalType();
}
if (conflicting(M->getASTContext(), FoundSignature, FoundSignatureType,
OtherSignature, OtherSignatureType,
/*wouldConflictInSwift5*/nullptr,
/*skipProtocolExtensionCheck*/true)) {
FoundConflicting = true;
if (!AvailableAttr::isUnavailable(VD)) {
bool preferVD = (
// Prefer derived requirements over their witnesses.
Reason == DeclVisibilityKind::
MemberOfProtocolDerivedByCurrentNominal ||
// Prefer available one.
AvailableAttr::isUnavailable(OtherVD) ||
// Prefer more accessible one.
VD->getFormalAccess() > OtherVD->getFormalAccess());
if (preferVD) {
FilteredResults.remove(
FoundDeclTy(OtherVD, DeclVisibilityKind::LocalVariable, {}));
FilteredResults.insert(DeclAndReason);
*I = VD;
}
}
}
}
if (!FoundConflicting) {
FilteredResults.insert(DeclAndReason);
PossiblyConflicting.push_back(VD);
}
}
for (auto Result : FilteredResults)
Consumer.foundDecl(Result.D, Result.Reason, Result.dynamicLookupInfo);
}
bool seenBaseName(DeclBaseName name) {
return DeclsByName.find(name) != DeclsByName.end();
}
};
struct KeyPathDynamicMemberConsumer : public VisibleDeclConsumer {
VisibleDeclConsumer &consumer;
std::function<bool(DeclBaseName)> seenStaticBaseName;
llvm::DenseSet<DeclBaseName> seen;
SubscriptDecl *currentSubscript = nullptr;
Type currentBaseType = Type();
KeyPathDynamicMemberConsumer(VisibleDeclConsumer &consumer,
std::function<bool(DeclBaseName)> seenBaseName)
: consumer(consumer), seenStaticBaseName(std::move(seenBaseName)) {}
bool checkShadowed(ValueDecl *VD) {
// Dynamic lookup members are only visible if they are not shadowed by
// other members.
return !isa<SubscriptDecl>(VD) && seen.insert(VD->getBaseName()).second &&
!seenStaticBaseName(VD->getBaseName());
}
void foundDecl(ValueDecl *VD, DeclVisibilityKind reason,
DynamicLookupInfo dynamicLookupInfo) override {
assert(dynamicLookupInfo.getKind() !=
DynamicLookupInfo::KeyPathDynamicMember);
// Only variables and subscripts are allowed in a keypath.
if (!isa<AbstractStorageDecl>(VD))
return;
// Dynamic lookup members are only visible if they are not shadowed by
// non-dynamic members.
if (checkShadowed(VD))
consumer.foundDecl(VD, DeclVisibilityKind::DynamicLookup,
{currentSubscript, currentBaseType, reason});
}
struct SubscriptChange {
KeyPathDynamicMemberConsumer &consumer;
SubscriptDecl *oldSubscript;
Type oldBaseType;
SubscriptChange(KeyPathDynamicMemberConsumer &consumer,
SubscriptDecl *newSubscript, Type newBaseType)
: consumer(consumer), oldSubscript(newSubscript),
oldBaseType(newBaseType) {
std::swap(consumer.currentSubscript, oldSubscript);
std::swap(consumer.currentBaseType, oldBaseType);
}
~SubscriptChange() {
consumer.currentSubscript = oldSubscript;
consumer.currentBaseType = oldBaseType;
}
};
};
} // end anonymous namespace
static void lookupVisibleDynamicMemberLookupDecls(
Type baseType, KeyPathDynamicMemberConsumer &consumer,
const DeclContext *dc, LookupState LS, DeclVisibilityKind reason,
GenericSignatureBuilder *GSB, VisitedSet &visited,
llvm::DenseSet<TypeBase *> &seenDynamicLookup);
/// Enumerates all members of \c baseType, including both directly visible and
/// members visible by keypath dynamic member lookup.
///
/// \note This is an implementation detail of \c lookupVisibleMemberDecls and
/// exists to create the correct recursion for dynamic member lookup.
static void lookupVisibleMemberAndDynamicMemberDecls(
Type baseType, VisibleDeclConsumer &consumer,
KeyPathDynamicMemberConsumer &dynamicMemberConsumer, const DeclContext *DC,
LookupState LS, DeclVisibilityKind reason, GenericSignatureBuilder *GSB,
VisitedSet &visited, llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
lookupVisibleMemberDeclsImpl(baseType, consumer, DC, LS, reason, GSB, visited);
lookupVisibleDynamicMemberLookupDecls(baseType, dynamicMemberConsumer, DC, LS,
reason, GSB, visited, seenDynamicLookup);
}
/// Enumerates all keypath dynamic members of \c baseType, as seen from the
/// context \c dc.
///
/// If \c baseType is \c \@dynamicMemberLookup, this looks up any keypath
/// dynamic member subscripts and looks up the members of the keypath's root
/// type.
static void lookupVisibleDynamicMemberLookupDecls(
Type baseType, KeyPathDynamicMemberConsumer &consumer,
const DeclContext *dc, LookupState LS, DeclVisibilityKind reason,
GenericSignatureBuilder *GSB, VisitedSet &visited,
llvm::DenseSet<TypeBase *> &seenDynamicLookup) {
if (!seenDynamicLookup.insert(baseType.getPointer()).second)
return;
if (!baseType->hasDynamicMemberLookupAttribute())
return;
auto &ctx = dc->getASTContext();
// Lookup the `subscript(dynamicMember:)` methods in this type.
DeclNameRef subscriptName(
{ ctx, DeclBaseName::createSubscript(), { ctx.Id_dynamicMember} });
SmallVector<ValueDecl *, 2> subscripts;
dc->lookupQualified(baseType, subscriptName,
NL_QualifiedDefault | NL_ProtocolMembers, subscripts);
for (ValueDecl *VD : subscripts) {
auto *subscript = dyn_cast<SubscriptDecl>(VD);
if (!subscript)
continue;
auto rootType = evaluateOrDefault(subscript->getASTContext().evaluator,
RootTypeOfKeypathDynamicMemberRequest{subscript}, Type());
if (rootType.isNull())
continue;
auto subs =
baseType->getMemberSubstitutionMap(dc->getParentModule(), subscript);
auto memberType = rootType.subst(subs);
if (!memberType->mayHaveMembers())
continue;
KeyPathDynamicMemberConsumer::SubscriptChange sub(consumer, subscript,
baseType);
lookupVisibleMemberAndDynamicMemberDecls(memberType, consumer, consumer, dc,
LS, reason, GSB, visited,
seenDynamicLookup);
}
}
/// 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, GenericSignatureBuilder *GSB) {
OverrideFilteringConsumer overrideConsumer(BaseTy, CurrDC);
KeyPathDynamicMemberConsumer dynamicConsumer(
Consumer,
[&](DeclBaseName name) { return overrideConsumer.seenBaseName(name); });
VisitedSet Visited;
llvm::DenseSet<TypeBase *> seenDynamicLookup;
lookupVisibleMemberAndDynamicMemberDecls(
BaseTy, overrideConsumer, dynamicConsumer, CurrDC, LS, Reason,
GSB, Visited, seenDynamicLookup);
// Report the declarations we found to the real consumer.
overrideConsumer.filterDecls(Consumer);
}
static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
const DeclContext *DC,
bool IncludeTopLevel, SourceLoc Loc) {
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()) {
GenericParamList *GenericParams = nullptr;
Type ExtendedType;
auto LS = LookupState::makeUnqualified();
LS = LS.withIncludeProtocolExtensionMembers();
// Skip initializer contexts, we will not find any declarations there.
if (isa<Initializer>(DC)) {
// For non-'lazy' decls, lookup on the meta type.
if (!isa<PatternBindingInitializer>(DC) ||
!cast<PatternBindingInitializer>(DC)->getInitializedLazyVar())
LS = LS.withOnMetatype();
DC = DC->getParent();
}
// 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();
if (SE->isStatic())
LS = LS.withOnMetatype();
} 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->getBodySourceRange().isValid() &&
SM.rangeContainsTokenLoc(AFD->getBodySourceRange(), Loc) &&
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());
GenericParams = AFD->getGenericParams();
if (AFD->getDeclContext()->isTypeContext()) {
ExtendedType = AFD->getDeclContext()->getSelfTypeInContext();
DC = DC->getParent();
if (auto *FD = dyn_cast<FuncDecl>(AFD))
if (FD->isStatic())
LS = LS.withOnMetatype();
}
} 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();
} else if (auto ND = dyn_cast<NominalTypeDecl>(DC)) {
ExtendedType = ND->getSelfTypeInContext();
}
// 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);
}
// Check the generic parameters of our context.
GenericParamList *dcGenericParams = nullptr;
if (auto nominal = dyn_cast<NominalTypeDecl>(DC))
dcGenericParams = nominal->getGenericParams();
else if (auto ext = dyn_cast<ExtensionDecl>(DC))
dcGenericParams = ext->getGenericParams();
else if (auto subscript = dyn_cast<SubscriptDecl>(DC))
dcGenericParams = subscript->getGenericParams();
while (dcGenericParams) {
namelookup::FindLocalVal localVal(SM, Loc, Consumer);
localVal.checkGenericParams(dcGenericParams);
dcGenericParams = dcGenericParams->getOuterParameters();
}
if (ExtendedType)
::lookupVisibleMemberDecls(ExtendedType, Consumer, DC, LS, Reason,
nullptr);
DC = DC->getParent();
Reason = DeclVisibilityKind::MemberOfOutsideNominal;
}
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;
}
}
}
if (IncludeTopLevel) {
using namespace namelookup;
SmallVector<ValueDecl *, 0> moduleResults;
lookupVisibleDeclsInModule(DC, {}, moduleResults,
NLKind::UnqualifiedLookup,
ResolutionKind::Overloadable,
DC);
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,
bool IncludeTopLevel,
SourceLoc Loc) {
if (Loc.isInvalid()) {
lookupVisibleDeclsImpl(Consumer, DC, IncludeTopLevel, Loc);
return;
}
UsableFilteringDeclConsumer FilteringConsumer(DC->getASTContext().SourceMgr,
DC, Loc, Consumer);
lookupVisibleDeclsImpl(FilteringConsumer, DC, IncludeTopLevel, Loc);
}
void swift::lookupVisibleMemberDecls(VisibleDeclConsumer &Consumer, Type BaseTy,
const DeclContext *CurrDC,
bool includeInstanceMembers,
bool includeDerivedRequirements,
bool includeProtocolExtensionMembers,
GenericSignatureBuilder *GSB) {
assert(CurrDC);
LookupState ls = LookupState::makeQualified();
if (includeInstanceMembers) {
ls = ls.withIncludedInstanceMembers();
}
if (includeDerivedRequirements) {
ls = ls.withIncludedDerivedRequirements();
}
if (includeProtocolExtensionMembers) {
ls = ls.withIncludeProtocolExtensionMembers();
}
::lookupVisibleMemberDecls(BaseTy, Consumer, CurrDC, ls,
DeclVisibilityKind::MemberOfCurrentNominal,
GSB);
}