mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
162 lines
4.8 KiB
C++
162 lines
4.8 KiB
C++
//===--- Evaluator.cpp - Request Evaluator Implementation -----------------===//
|
|
//
|
|
// 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 Evaluator class that evaluates and caches
|
|
// requests.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "swift/AST/Evaluator.h"
|
|
#include "swift/AST/DiagnosticEngine.h"
|
|
#include "swift/Basic/LangOptions.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Basic/SourceManager.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/SaveAndRestore.h"
|
|
#include <vector>
|
|
|
|
using namespace swift;
|
|
|
|
std::string AnyRequest::getAsString() const {
|
|
std::string result;
|
|
{
|
|
llvm::raw_string_ostream out(result);
|
|
simple_display(out, *this);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
AbstractRequestFunction *
|
|
Evaluator::getAbstractRequestFunction(uint8_t zoneID, uint8_t requestID) const {
|
|
for (const auto &zone : requestFunctionsByZone) {
|
|
if (zone.first == zoneID) {
|
|
if (requestID < zone.second.size())
|
|
return zone.second[requestID];
|
|
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void Evaluator::registerRequestFunctions(
|
|
Zone zone,
|
|
ArrayRef<AbstractRequestFunction *> functions) {
|
|
uint8_t zoneID = static_cast<uint8_t>(zone);
|
|
#ifndef NDEBUG
|
|
for (const auto &zone : requestFunctionsByZone) {
|
|
assert(zone.first != zoneID);
|
|
}
|
|
#endif
|
|
|
|
requestFunctionsByZone.push_back({zoneID, functions});
|
|
}
|
|
|
|
Evaluator::Evaluator(DiagnosticEngine &diags, const LangOptions &opts)
|
|
: diags(diags),
|
|
debugDumpCycles(opts.DebugDumpCycles),
|
|
recorder(opts.RecordRequestReferences) {}
|
|
|
|
bool Evaluator::checkDependency(const ActiveRequest &request) {
|
|
// Record this as an active request.
|
|
if (activeRequests.insert(request))
|
|
return false;
|
|
|
|
// Diagnose cycle.
|
|
diagnoseCycle(request);
|
|
return true;
|
|
}
|
|
|
|
void Evaluator::diagnoseCycle(const ActiveRequest &request) {
|
|
if (debugDumpCycles) {
|
|
llvm::errs() << "===CYCLE DETECTED===\n";
|
|
for (auto &req : activeRequests) {
|
|
simple_display(llvm::errs(), AnyRequest(req));
|
|
llvm::errs() << "\n";
|
|
}
|
|
}
|
|
|
|
request.diagnoseCycle(diags);
|
|
for (const auto &step : llvm::reverse(activeRequests)) {
|
|
if (step == request) return;
|
|
|
|
step.noteCycleStep(diags);
|
|
}
|
|
|
|
llvm_unreachable("Diagnosed a cycle but it wasn't represented in the stack");
|
|
}
|
|
|
|
void evaluator::DependencyRecorder::recordDependency(
|
|
const DependencyCollector::Reference &ref) {
|
|
if (activeRequestReferences.empty())
|
|
return;
|
|
|
|
activeRequestReferences.back().insert(ref);
|
|
}
|
|
|
|
evaluator::DependencyCollector::DependencyCollector(
|
|
evaluator::DependencyRecorder &parent) : parent(parent) {
|
|
#ifndef NDEBUG
|
|
assert(!parent.isRecording &&
|
|
"Probably not a good idea to allow nested recording");
|
|
parent.isRecording = true;
|
|
#endif
|
|
}
|
|
|
|
evaluator::DependencyCollector::~DependencyCollector() {
|
|
#ifndef NDEBUG
|
|
assert(parent.isRecording &&
|
|
"Should have been recording this whole time");
|
|
parent.isRecording = false;
|
|
#endif
|
|
}
|
|
|
|
void evaluator::DependencyCollector::addUsedMember(NominalTypeDecl *subject,
|
|
DeclBaseName name) {
|
|
return parent.recordDependency(Reference::usedMember(subject, name));
|
|
}
|
|
|
|
void evaluator::DependencyCollector::addPotentialMember(
|
|
NominalTypeDecl *subject) {
|
|
return parent.recordDependency(Reference::potentialMember(subject));
|
|
}
|
|
|
|
void evaluator::DependencyCollector::addTopLevelName(DeclBaseName name) {
|
|
return parent.recordDependency(Reference::topLevel(name));
|
|
}
|
|
|
|
void evaluator::DependencyCollector::addDynamicLookupName(DeclBaseName name) {
|
|
return parent.recordDependency(Reference::dynamic(name));
|
|
}
|
|
|
|
void evaluator::DependencyRecorder::enumerateReferencesInFile(
|
|
const SourceFile *SF, ReferenceEnumerator f) const {
|
|
auto entry = fileReferences.find(SF);
|
|
if (entry == fileReferences.end()) {
|
|
return;
|
|
}
|
|
|
|
for (const auto &ref : entry->getSecond()) {
|
|
switch (ref.kind) {
|
|
case DependencyCollector::Reference::Kind::Empty:
|
|
case DependencyCollector::Reference::Kind::Tombstone:
|
|
llvm_unreachable("Cannot enumerate dead reference!");
|
|
case DependencyCollector::Reference::Kind::UsedMember:
|
|
case DependencyCollector::Reference::Kind::PotentialMember:
|
|
case DependencyCollector::Reference::Kind::TopLevel:
|
|
case DependencyCollector::Reference::Kind::Dynamic:
|
|
f(ref);
|
|
}
|
|
}
|
|
}
|