Files
swift-mirror/lib/AST/NameLookupRequests.cpp
Robert Widmann dfdebfaddf [NFC] Gate Cross-Module Dependency Sinks on Incremental Info
This has the net effect of only recording cross-module dependency information in the current module if the module under scrutiny can possibly provide dependency information of its own.

For now, because none of this is turned on, this does not actually record additional dependencies from extant modules.
2020-09-24 20:07:02 -06:00

401 lines
14 KiB
C++

//===--- NameLookupRequests.cpp - Name Lookup Requests --------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "swift/AST/NameLookup.h"
#include "swift/AST/NameLookupRequests.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/Evaluator.h"
#include "swift/AST/Module.h"
#include "swift/AST/SourceFile.h"
#include "swift/Subsystems.h"
using namespace swift;
namespace swift {
// Implement the name lookup type zone.
#define SWIFT_TYPEID_ZONE NameLookup
#define SWIFT_TYPEID_HEADER "swift/AST/NameLookupTypeIDZone.def"
#include "swift/Basic/ImplementTypeIDZone.h"
#undef SWIFT_TYPEID_ZONE
#undef SWIFT_TYPEID_HEADER
}
//----------------------------------------------------------------------------//
// Referenced inherited decls computation.
//----------------------------------------------------------------------------//
SourceLoc InheritedDeclsReferencedRequest::getNearestLoc() const {
const auto &storage = getStorage();
auto &typeLoc = getInheritedTypeLocAtIndex(std::get<0>(storage),
std::get<1>(storage));
return typeLoc.getLoc();
}
//----------------------------------------------------------------------------//
// Superclass declaration computation.
//----------------------------------------------------------------------------//
Optional<ClassDecl *> SuperclassDeclRequest::getCachedResult() const {
auto nominalDecl = std::get<0>(getStorage());
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
if (classDecl->LazySemanticInfo.SuperclassDecl.getInt())
return classDecl->LazySemanticInfo.SuperclassDecl.getPointer();
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(nominalDecl))
if (protocolDecl->LazySemanticInfo.SuperclassDecl.getInt())
return protocolDecl->LazySemanticInfo.SuperclassDecl.getPointer();
return None;
}
void SuperclassDeclRequest::cacheResult(ClassDecl *value) const {
auto nominalDecl = std::get<0>(getStorage());
if (auto *classDecl = dyn_cast<ClassDecl>(nominalDecl))
classDecl->LazySemanticInfo.SuperclassDecl.setPointerAndInt(value, true);
if (auto *protocolDecl = dyn_cast<ProtocolDecl>(nominalDecl))
protocolDecl->LazySemanticInfo.SuperclassDecl.setPointerAndInt(value, true);
}
//----------------------------------------------------------------------------//
// InheritedProtocolsRequest computation.
//----------------------------------------------------------------------------//
Optional<ArrayRef<ProtocolDecl *>>
InheritedProtocolsRequest::getCachedResult() const {
auto proto = std::get<0>(getStorage());
if (!proto->areInheritedProtocolsValid())
return None;
return proto->InheritedProtocols;
}
void InheritedProtocolsRequest::cacheResult(ArrayRef<ProtocolDecl *> PDs) const {
auto proto = std::get<0>(getStorage());
proto->InheritedProtocols = PDs;
proto->setInheritedProtocolsValid();
}
void InheritedProtocolsRequest::writeDependencySink(
evaluator::DependencyCollector &tracker,
ArrayRef<ProtocolDecl *> PDs) const {
for (auto *parentProto : PDs) {
tracker.addPotentialMember(parentProto);
}
}
//----------------------------------------------------------------------------//
// Missing designated initializers computation
//----------------------------------------------------------------------------//
Optional<bool> HasMissingDesignatedInitializersRequest::getCachedResult() const {
auto classDecl = std::get<0>(getStorage());
return classDecl->getCachedHasMissingDesignatedInitializers();
}
void HasMissingDesignatedInitializersRequest::cacheResult(bool result) const {
auto classDecl = std::get<0>(getStorage());
classDecl->setHasMissingDesignatedInitializers(result);
}
bool
HasMissingDesignatedInitializersRequest::evaluate(Evaluator &evaluator,
ClassDecl *subject) const {
// Short-circuit and check for the attribute here.
if (subject->getAttrs().hasAttribute<HasMissingDesignatedInitializersAttr>())
return true;
AccessScope scope =
subject->getFormalAccessScope(/*useDC*/nullptr,
/*treatUsableFromInlineAsPublic*/true);
// This flag only makes sense for public types that will be written in the
// module.
if (!scope.isPublic())
return false;
auto constructors = subject->lookupDirect(DeclBaseName::createConstructor());
return llvm::any_of(constructors, [&](ValueDecl *decl) {
auto init = cast<ConstructorDecl>(decl);
if (!init->isDesignatedInit())
return false;
AccessScope scope =
init->getFormalAccessScope(/*useDC*/nullptr,
/*treatUsableFromInlineAsPublic*/true);
return !scope.isPublic();
});
}
//----------------------------------------------------------------------------//
// Extended nominal computation.
//----------------------------------------------------------------------------//
Optional<NominalTypeDecl *> ExtendedNominalRequest::getCachedResult() const {
// Note: if we fail to compute any nominal declaration, it's considered
// a cache miss. This allows us to recompute the extended nominal types
// during extension binding.
// This recomputation is also what allows you to extend types defined inside
// other extensions, regardless of source file order. See \c bindExtensions(),
// which uses a worklist algorithm that attempts to bind everything until
// fixed point.
auto ext = std::get<0>(getStorage());
if (!ext->hasBeenBound() || !ext->getExtendedNominal())
return None;
return ext->getExtendedNominal();
}
void ExtendedNominalRequest::cacheResult(NominalTypeDecl *value) const {
auto ext = std::get<0>(getStorage());
ext->setExtendedNominal(value);
}
void ExtendedNominalRequest::writeDependencySink(
evaluator::DependencyCollector &tracker, NominalTypeDecl *value) const {
if (!value)
return;
// Ensure this extension comes from a source file.
auto *SF = std::get<0>(getStorage())->getParentSourceFile();
if (!SF)
return;
if (SF != tracker.getRecorder().getActiveDependencySourceOrNull().getPtrOrNull())
return;
tracker.addPotentialMember(value);
}
//----------------------------------------------------------------------------//
// Destructor computation.
//----------------------------------------------------------------------------//
Optional<DestructorDecl *> GetDestructorRequest::getCachedResult() const {
auto *classDecl = std::get<0>(getStorage());
auto results = classDecl->lookupDirect(DeclBaseName::createDestructor());
if (results.empty())
return None;
return cast<DestructorDecl>(results.front());
}
void GetDestructorRequest::cacheResult(DestructorDecl *value) const {
auto *classDecl = std::get<0>(getStorage());
classDecl->addMember(value);
}
//----------------------------------------------------------------------------//
// GenericParamListRequest computation.
//----------------------------------------------------------------------------//
Optional<GenericParamList *> GenericParamListRequest::getCachedResult() const {
auto *decl = std::get<0>(getStorage());
if (auto *params = decl->GenericParamsAndBit.getPointer())
return params;
if (decl->GenericParamsAndBit.getInt())
return nullptr;
return None;
}
void GenericParamListRequest::cacheResult(GenericParamList *params) const {
auto *context = std::get<0>(getStorage());
if (params)
params->setDeclContext(context);
context->GenericParamsAndBit.setPointerAndInt(params, true);
}
//----------------------------------------------------------------------------//
// UnqualifiedLookupRequest computation.
//----------------------------------------------------------------------------//
void swift::simple_display(llvm::raw_ostream &out,
const UnqualifiedLookupDescriptor &desc) {
out << "looking up ";
simple_display(out, desc.Name);
out << " from ";
simple_display(out, desc.DC);
out << " with options ";
simple_display(out, desc.Options);
}
SourceLoc
swift::extractNearestSourceLoc(const UnqualifiedLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.DC);
}
//----------------------------------------------------------------------------//
// DirectLookupRequest computation.
//----------------------------------------------------------------------------//
void swift::simple_display(llvm::raw_ostream &out,
const DirectLookupDescriptor &desc) {
out << "directly looking up ";
simple_display(out, desc.Name);
out << " on ";
simple_display(out, desc.DC);
out << " with options ";
simple_display(out, desc.Options);
}
SourceLoc swift::extractNearestSourceLoc(const DirectLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.DC);
}
//----------------------------------------------------------------------------//
// LookupOperatorRequest computation.
//----------------------------------------------------------------------------//
OperatorLookupDescriptor OperatorLookupDescriptor::forDC(const DeclContext *DC,
Identifier name) {
auto *moduleDC = DC->getModuleScopeContext();
if (auto *file = dyn_cast<FileUnit>(moduleDC)) {
return OperatorLookupDescriptor::forFile(file, name);
} else {
auto *mod = cast<ModuleDecl>(moduleDC->getAsDecl());
return OperatorLookupDescriptor::forModule(mod, name);
}
}
ArrayRef<FileUnit *> OperatorLookupDescriptor::getFiles() const {
if (auto *module = getModule())
return module->getFiles();
// Return an ArrayRef pointing to the FileUnit in the union.
return llvm::makeArrayRef(*fileOrModule.getAddrOfPtr1());
}
void swift::simple_display(llvm::raw_ostream &out,
const OperatorLookupDescriptor &desc) {
out << "looking up operator ";
simple_display(out, desc.name);
out << " in ";
simple_display(out, desc.fileOrModule);
}
SourceLoc swift::extractNearestSourceLoc(const OperatorLookupDescriptor &desc) {
return extractNearestSourceLoc(desc.fileOrModule);
}
void DirectLookupRequest::writeDependencySink(
evaluator::DependencyCollector &tracker,
TinyPtrVector<ValueDecl *> result) const {
auto &desc = std::get<0>(getStorage());
tracker.addUsedMember(desc.DC, desc.Name.getBaseName());
}
//----------------------------------------------------------------------------//
// LookupInModuleRequest computation.
//----------------------------------------------------------------------------//
void LookupInModuleRequest::writeDependencySink(
evaluator::DependencyCollector &reqTracker, QualifiedLookupResult l) const {
auto *DC = std::get<0>(getStorage());
auto member = std::get<1>(getStorage());
// Decline to record lookups if the module in question has no incremental
// dependency information available.
auto *module = DC->getParentModule();
if (module->isMainModule() || module->hasIncrementalInfo()) {
reqTracker.addTopLevelName(member.getBaseName());
}
}
//----------------------------------------------------------------------------//
// LookupConformanceInModuleRequest computation.
//----------------------------------------------------------------------------//
void swift::simple_display(llvm::raw_ostream &out,
const LookupConformanceDescriptor &desc) {
out << "looking up conformance to ";
simple_display(out, desc.PD);
out << " for ";
out << desc.Ty.getString();
out << " in ";
simple_display(out, desc.Mod);
}
void AnyObjectLookupRequest::writeDependencySink(
evaluator::DependencyCollector &reqTracker, QualifiedLookupResult l) const {
auto member = std::get<1>(getStorage());
reqTracker.addDynamicLookupName(member.getBaseName());
}
SourceLoc
swift::extractNearestSourceLoc(const LookupConformanceDescriptor &desc) {
return SourceLoc();
}
//----------------------------------------------------------------------------//
// ModuleQualifiedLookupRequest computation.
//----------------------------------------------------------------------------//
void ModuleQualifiedLookupRequest::writeDependencySink(
evaluator::DependencyCollector &reqTracker, QualifiedLookupResult l) const {
auto *module = std::get<1>(getStorage());
auto member = std::get<2>(getStorage());
// Decline to record lookups if the module in question has no incremental
// dependency information available.
if (module->isMainModule() || module->hasIncrementalInfo()) {
reqTracker.addTopLevelName(member.getBaseName());
}
}
//----------------------------------------------------------------------------//
// LookupConformanceInModuleRequest computation.
//----------------------------------------------------------------------------//
void LookupConformanceInModuleRequest::writeDependencySink(
evaluator::DependencyCollector &reqTracker,
ProtocolConformanceRef lookupResult) const {
if (lookupResult.isInvalid() || !lookupResult.isConcrete())
return;
auto &desc = std::get<0>(getStorage());
auto *Adoptee = desc.Ty->getAnyNominal();
if (!Adoptee)
return;
// Decline to record lookups if the module in question has no incremental
// dependency information available.
auto *conformance = lookupResult.getConcrete();
auto *module = conformance->getDeclContext()->getParentModule();
if (module->isMainModule() || module->hasIncrementalInfo()) {
reqTracker.addPotentialMember(Adoptee);
}
}
//----------------------------------------------------------------------------//
// UnqualifiedLookupRequest computation.
//----------------------------------------------------------------------------//
void UnqualifiedLookupRequest::writeDependencySink(
evaluator::DependencyCollector &track, LookupResult res) const {
auto &desc = std::get<0>(getStorage());
track.addTopLevelName(desc.Name.getBaseName());
}
// Define request evaluation functions for each of the name lookup requests.
static AbstractRequestFunction *nameLookupRequestFunctions[] = {
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluateRequest),
#include "swift/AST/NameLookupTypeIDZone.def"
#undef SWIFT_REQUEST
};
void swift::registerNameLookupRequestFunctions(Evaluator &evaluator) {
evaluator.registerRequestFunctions(Zone::NameLookup,
nameLookupRequestFunctions);
}