Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 57 additions & 141 deletions lib/AST/LookupVisibleDecls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -230,27 +230,8 @@ static void lookupTypeMembers(Type BaseType, Type LookupType,
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))
Expand Down Expand Up @@ -471,92 +452,6 @@ lookupVisibleMemberDeclsImpl(Type BaseTy, VisibleDeclConsumer &Consumer,
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,
Expand Down Expand Up @@ -642,12 +537,11 @@ static void lookupVisibleMemberDeclsImpl(
for (auto Proto : Archetype->getConformsTo())
lookupVisibleProtocolMemberDecls(
BaseTy, Proto->getDeclaredType(), Consumer, CurrDC, LS,
getReasonForSuper(Reason), TypeResolver, GSB, Visited);
Reason, TypeResolver, GSB, Visited);

if (auto superclass = Archetype->getSuperclass())
lookupVisibleMemberDeclsImpl(superclass, Consumer, CurrDC, LS,
getReasonForSuper(Reason), TypeResolver,
GSB, Visited);
Reason, TypeResolver, GSB, Visited);
return;
}

Expand Down Expand Up @@ -766,19 +660,25 @@ template <> struct DenseMapInfo<FoundDeclTy> {

} // 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;
// 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, 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 false;
return BaseTy;
}

namespace {

class OverrideFilteringConsumer : public VisibleDeclConsumer {
public:
std::set<ValueDecl *> AllFoundDecls;
Expand All @@ -787,16 +687,12 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
Type BaseTy;
const DeclContext *DC;
LazyResolver *TypeResolver;
bool IsTypeLookup = false;

OverrideFilteringConsumer(Type BaseTy, const DeclContext *DC,
LazyResolver *resolver)
: BaseTy(BaseTy), DC(DC), TypeResolver(resolver) {
: BaseTy(BaseTy->getMetatypeInstanceType()),
DC(DC), TypeResolver(resolver) {
assert(!BaseTy->hasLValueType());
if (auto *MetaTy = BaseTy->getAs<AnyMetatypeType>()) {
BaseTy = MetaTy->getInstanceType();
IsTypeLookup = true;
}
assert(DC && BaseTy);
}

Expand All @@ -806,7 +702,9 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {

// If this kind of declaration doesn't participate in overriding, there's
// no filtering to do here.
if (!isa<AbstractFunctionDecl>(VD) && !isa<AbstractStorageDecl>(VD)) {
if (!isa<AbstractFunctionDecl>(VD) &&
!isa<AbstractStorageDecl>(VD) &&
!isa<AssociatedTypeDecl>(VD)) {
DeclsToReport.insert(FoundDeclTy(VD, Reason));
return;
}
Expand Down Expand Up @@ -857,7 +755,8 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {
// don't substitute either.
bool shouldSubst = (!BaseTy->isAnyObject() &&
!BaseTy->hasTypeVariable() &&
BaseTy->getNominalOrBoundGenericNominal() &&
(BaseTy->getNominalOrBoundGenericNominal() ||
BaseTy->is<ArchetypeType>()) &&
VD->getDeclContext()->isTypeContext());
ModuleDecl *M = DC->getParentModule();

Expand All @@ -870,8 +769,7 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {

auto FoundSignature = VD->getOverloadSignature();
auto FoundSignatureType = VD->getOverloadSignatureType();
if (FoundSignatureType && shouldSubst &&
shouldSubstIntoDeclType(FoundSignatureType)) {
if (FoundSignatureType && shouldSubst) {
auto subs = BaseTy->getMemberSubstitutionMap(M, VD);
if (auto CT = FoundSignatureType.subst(subs))
FoundSignatureType = CT->getCanonicalType();
Expand All @@ -888,9 +786,9 @@ class OverrideFilteringConsumer : public VisibleDeclConsumer {

auto OtherSignature = OtherVD->getOverloadSignature();
auto OtherSignatureType = OtherVD->getOverloadSignatureType();
if (OtherSignatureType && shouldSubst &&
shouldSubstIntoDeclType(OtherSignatureType)) {
auto subs = BaseTy->getMemberSubstitutionMap(M, OtherVD);
if (OtherSignatureType && shouldSubst) {
auto ActualBaseTy = getBaseTypeForMember(M, OtherVD, BaseTy);
auto subs = ActualBaseTy->getMemberSubstitutionMap(M, OtherVD);
if (auto CT = OtherSignatureType.subst(subs))
OtherSignatureType = CT->getCanonicalType();
}
Expand Down Expand Up @@ -931,13 +829,11 @@ static void lookupVisibleMemberDecls(
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,
lookupVisibleMemberDeclsImpl(BaseTy, overrideConsumer, 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);
}
Expand All @@ -953,7 +849,7 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
// 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;
GenericParamList *GenericParams = nullptr;
Type ExtendedType;
auto LS = LookupState::makeUnqualified();

Expand All @@ -977,7 +873,6 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
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
Expand All @@ -996,9 +891,10 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
namelookup::FindLocalVal(SM, Loc, Consumer).checkParameterList(
AFD->getParameters());

GenericParams = AFD->getGenericParams();

if (AFD->getDeclContext()->isTypeContext()) {
ExtendedType = AFD->getDeclContext()->getSelfTypeInContext();
BaseDecl = AFD->getImplicitSelfDecl();
DC = DC->getParent();

if (auto *FD = dyn_cast<FuncDecl>(AFD))
Expand All @@ -1014,14 +910,34 @@ static void lookupVisibleDeclsImpl(VisibleDeclConsumer &Consumer,
}
} 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)
// 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,
TypeResolver, nullptr);

Expand Down
3 changes: 1 addition & 2 deletions lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ Type TypeBase::addCurriedSelfType(const DeclContext *dc) {
genericFn->getExtInfo());
}

auto selfTy = dc->getDeclaredInterfaceType();
auto selfTy = dc->getSelfInterfaceType();
auto selfParam = AnyFunctionType::Param(selfTy);
if (sig)
return GenericFunctionType::get(sig, {selfParam}, type);
Expand Down Expand Up @@ -860,7 +860,6 @@ Type TypeBase::getMetatypeInstanceType() {
if (auto metaTy = getAs<AnyMetatypeType>())
return metaTy->getInstanceType();

// For mutable value type methods, we need to dig through inout types.
return this;
}

Expand Down
Loading