mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 20:10:13 +01:00
Trace output filtering based on file context (#2916)
To filter based on file contexts, you can use `-trace_file_context=...` flag along with `--trace_file=...` flag. These are the following options you can pass to the `-trace_file_context=...` flag (you can also pass them as list by separating them with comma). 1. `main`: Include trace output for file containing the main function. 2. `prelude`: Include trace output for prelude. 3. `import`: Include trace output for imports. 4. `include`: Include trace output for all. If the flag isn't used or non of the options are passed, by default only main file context is traced. File contexts are distinguished based upon the source location by passing the source location to `TraceStream::is_enabled(..)` as arguments. If no arguments are passed, file context is `FileContext::Unknown` and for now it will add the trace from unknown file context. Note: `import` option currently doesn't work as imports aren't supported yet. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
037196f69f
commit
c0d18a62eb
+25
-14
@@ -168,24 +168,35 @@ performed during execution.
|
||||
Printing directly to the standard output using the `--trace_file` option is
|
||||
supported by passing `-` in place of a filepath (`--trace_file=-`).
|
||||
|
||||
To customize the trace output and include specific information, you can pass the
|
||||
following list of options to `-trace_phase=...` option along with
|
||||
`--trace_file=...` option:
|
||||
Trace output can be customized by selecting program phases and file contexts for
|
||||
which tracing should be enabled. The `-trace_phase=...` option is used to select
|
||||
program phases, while the `-trace_file_context=...` option is used to select
|
||||
file contexts.
|
||||
|
||||
- `source_program`: Include trace output for the source program phase.
|
||||
- `name_resolution`: Include trace output for the name resolution phase.
|
||||
- `control_flow_resolution`: Include trace output for the control flow
|
||||
The following options can be passed as a comma-separated list to the
|
||||
`-trace_phase=...` option to select program phases:
|
||||
|
||||
- `source_program`: Includes trace output for the source program phase.
|
||||
- `name_resolution`: Includes trace output for the name resolution phase.
|
||||
- `control_flow_resolution`: Includes trace output for the control flow
|
||||
resolution phase.
|
||||
- `type_checking`: Include trace output for the type checking phase.
|
||||
- `unformed_variables_resolution`: Include trace output for the unformed
|
||||
- `type_checking`: Includes trace output for the type checking phase.
|
||||
- `unformed_variables_resolution`: Includes trace output for the unformed
|
||||
variables resolution phase.
|
||||
- `declarations`: Include trace output for printing declarations.
|
||||
- `execution`: Include trace output for program execution.
|
||||
- `timing`: Include timing logs indicating the time taken by each phase.
|
||||
- `all`: Include trace output for all phases.
|
||||
- `declarations`: Includes trace output for printing declarations.
|
||||
- `execution`: Includes trace output for program execution.
|
||||
- `timing`: Includes timing logs indicating the time taken by each phase.
|
||||
- `all`: Includes trace output for all phases.
|
||||
- By default, tracing is only enabled for the `execution` phase.
|
||||
|
||||
By default, only execution trace will be added to the trace output. You can use
|
||||
combination of these options to include trace of multiple program phases.
|
||||
The following options can be passed as a comma-separated list to the
|
||||
`-trace_file_context=...` option to select file contexts:
|
||||
|
||||
- `main`: Includes trace output for the file containing the main function.
|
||||
- `prelude`: Includes trace output for the prelude.
|
||||
- `import`: Includes trace output for imports.
|
||||
- `include`: Includes trace output for all.
|
||||
- By default, tracing is only enabled for the `main` file context.
|
||||
|
||||
### State of the Program
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ cc_library(
|
||||
name = "trace_stream",
|
||||
hdrs = ["trace_stream.h"],
|
||||
deps = [
|
||||
":source_location",
|
||||
"//common:check",
|
||||
"//common:ostream",
|
||||
"//explorer/common:nonnull",
|
||||
@@ -69,3 +70,14 @@ cc_test(
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "set_file_context_raii_test",
|
||||
srcs = ["set_file_context_raii_test.cpp"],
|
||||
deps = [
|
||||
":source_location",
|
||||
":trace_stream",
|
||||
"//testing/util:gtest_main",
|
||||
"@com_google_googletest//:gtest",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "explorer/common/trace_stream.h"
|
||||
|
||||
namespace Carbon::Testing {
|
||||
namespace {
|
||||
|
||||
// TODO: write test cases to distinguish between file context of main file and
|
||||
// an import once imports are supported.
|
||||
|
||||
TEST(SetFileContextRaiiTest, Simple) {
|
||||
TraceStream trace_stream;
|
||||
{
|
||||
SetFileContext set_file_ctx(trace_stream,
|
||||
SourceLocation("example/main.carbon", 9));
|
||||
EXPECT_TRUE(trace_stream.file_context() == FileContext::Main);
|
||||
}
|
||||
|
||||
// Considering the file context for a trace stream is FileContext::Unknown by
|
||||
// default, as the default value of source location in a trace stream is
|
||||
// std::nullopt.
|
||||
EXPECT_TRUE(trace_stream.file_context() == FileContext::Unknown);
|
||||
}
|
||||
|
||||
TEST(SetFileContextRaiiTest, UpdateFileContext) {
|
||||
TraceStream trace_stream;
|
||||
{
|
||||
SetFileContext set_file_ctx(trace_stream,
|
||||
SourceLocation("example/prelude.carbon", 9));
|
||||
EXPECT_TRUE(trace_stream.file_context() == FileContext::Prelude);
|
||||
set_file_ctx.update_source_loc(SourceLocation("example/main.carbon", 9));
|
||||
EXPECT_TRUE(trace_stream.file_context() == FileContext::Main);
|
||||
}
|
||||
|
||||
// Considering the file context for a trace stream is FileContext::Unknown by
|
||||
// default, as the default value of source location in a trace stream is
|
||||
// std::nullopt.
|
||||
EXPECT_TRUE(trace_stream.file_context() == FileContext::Unknown);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Carbon::Testing
|
||||
@@ -37,6 +37,8 @@ class SourceLocation {
|
||||
return filename_ == other.filename_ && line_num_ == other.line_num_;
|
||||
}
|
||||
|
||||
auto filename() const -> std::string_view { return filename_; }
|
||||
|
||||
void Print(llvm::raw_ostream& out) const {
|
||||
out << filename_ << ":" << line_num_;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "common/check.h"
|
||||
#include "common/ostream.h"
|
||||
#include "explorer/common/nonnull.h"
|
||||
#include "explorer/common/source_location.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
@@ -34,6 +35,10 @@ enum class ProgramPhase {
|
||||
Last = All // Last program phase indicator.
|
||||
};
|
||||
|
||||
// Enumerates the contexts for different types of files, used for tracing and
|
||||
// controlling for which file contexts tracing should be enabled.
|
||||
enum class FileContext { Unknown, Main, Prelude, Import, All, Last = All };
|
||||
|
||||
// Encapsulates the trace stream so that we can cleanly disable tracing while
|
||||
// the prelude is being processed. The prelude is expected to take a
|
||||
// disproprotionate amount of time to log, so we try to avoid it.
|
||||
@@ -45,12 +50,32 @@ enum class ProgramPhase {
|
||||
// contexts.
|
||||
class TraceStream {
|
||||
public:
|
||||
explicit TraceStream() { set_allowed_file_contexts({FileContext::Unknown}); }
|
||||
|
||||
// This method gets the file context by using filename from source location.
|
||||
// TODO: implement a way to differentiate between the main file and imports
|
||||
// based upon source location / filename.
|
||||
auto file_context() const -> FileContext {
|
||||
if (source_loc_.has_value()) {
|
||||
auto filename =
|
||||
llvm::StringRef(source_loc_->filename()).rsplit("/").second;
|
||||
if (filename == "prelude.carbon") {
|
||||
return FileContext::Prelude;
|
||||
} else {
|
||||
return FileContext::Main;
|
||||
}
|
||||
} else {
|
||||
return FileContext::Unknown;
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if tracing is currently enabled.
|
||||
// TODO: use current source location for file context based filtering instead
|
||||
// of just checking if current code context is Prelude.
|
||||
auto is_enabled() const -> bool {
|
||||
return stream_.has_value() && !in_prelude_ &&
|
||||
allowed_phases_[static_cast<int>(current_phase_)];
|
||||
allowed_phases_[static_cast<int>(current_phase_)] &&
|
||||
allowed_file_contexts_[static_cast<int>(file_context())];
|
||||
}
|
||||
|
||||
// Sets whether the prelude is being skipped.
|
||||
@@ -79,6 +104,29 @@ class TraceStream {
|
||||
}
|
||||
}
|
||||
|
||||
auto set_allowed_file_contexts(std::vector<FileContext> contexts_list)
|
||||
-> void {
|
||||
if (contexts_list.empty()) {
|
||||
allowed_file_contexts_.set(static_cast<int>(FileContext::Main));
|
||||
} else {
|
||||
for (auto context : contexts_list) {
|
||||
if (context == FileContext::All) {
|
||||
allowed_file_contexts_.set();
|
||||
} else {
|
||||
allowed_file_contexts_.set(static_cast<int>(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto set_source_loc(std::optional<SourceLocation> source_loc) {
|
||||
source_loc_ = source_loc;
|
||||
}
|
||||
|
||||
auto source_loc() -> std::optional<SourceLocation> { return source_loc_; }
|
||||
|
||||
auto allowed_phases() { return allowed_phases_; }
|
||||
|
||||
// Returns the internal stream. Requires is_enabled.
|
||||
auto stream() const -> llvm::raw_ostream& {
|
||||
CARBON_CHECK(is_enabled() && stream_.has_value());
|
||||
@@ -97,13 +145,15 @@ class TraceStream {
|
||||
|
||||
private:
|
||||
bool in_prelude_ = false;
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> stream_;
|
||||
ProgramPhase current_phase_ = ProgramPhase::Unknown;
|
||||
std::optional<SourceLocation> source_loc_ = std::nullopt;
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> stream_;
|
||||
std::bitset<static_cast<int>(ProgramPhase::Last) + 1> allowed_phases_;
|
||||
std::bitset<static_cast<int>(FileContext::Last) + 1> allowed_file_contexts_;
|
||||
};
|
||||
|
||||
// This is a RAII class to set the current program phase, destructor invocation
|
||||
// restores the previous phase
|
||||
// restores the previous phase.
|
||||
class SetProgramPhase {
|
||||
public:
|
||||
explicit SetProgramPhase(TraceStream& trace_stream,
|
||||
@@ -113,19 +163,43 @@ class SetProgramPhase {
|
||||
trace_stream.set_current_phase(program_phase);
|
||||
}
|
||||
|
||||
~SetProgramPhase() { trace_stream_.set_current_phase(initial_phase_); }
|
||||
|
||||
// This can be used for cases when current phase is set multiple times within
|
||||
// the same scope
|
||||
// the same scope.
|
||||
auto update_phase(ProgramPhase program_phase) -> void {
|
||||
trace_stream_.set_current_phase(program_phase);
|
||||
}
|
||||
|
||||
~SetProgramPhase() { trace_stream_.set_current_phase(initial_phase_); }
|
||||
|
||||
private:
|
||||
TraceStream& trace_stream_;
|
||||
ProgramPhase initial_phase_;
|
||||
};
|
||||
|
||||
// This is a RAII class to set the source location in trace stream, destructor
|
||||
// invocation restores the initial source location.
|
||||
class SetFileContext {
|
||||
public:
|
||||
explicit SetFileContext(TraceStream& trace_stream,
|
||||
std::optional<SourceLocation> source_loc)
|
||||
: trace_stream_(trace_stream),
|
||||
initial_source_loc_(trace_stream.source_loc()) {
|
||||
trace_stream_.set_source_loc(source_loc);
|
||||
}
|
||||
|
||||
~SetFileContext() { trace_stream_.set_source_loc(initial_source_loc_); }
|
||||
|
||||
// This can be used for cases when source location needs to be updated
|
||||
// multiple times within the same scope.
|
||||
auto update_source_loc(std::optional<SourceLocation> source_loc) {
|
||||
trace_stream_.set_source_loc(source_loc);
|
||||
}
|
||||
|
||||
private:
|
||||
TraceStream& trace_stream_;
|
||||
std::optional<SourceLocation> initial_source_loc_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
#endif // CARBON_EXPLORER_COMMON_TRACE_STREAM_H_
|
||||
|
||||
@@ -57,6 +57,7 @@ class ParseAndExecuteTestFile : public FileTestBase {
|
||||
if (trace_) {
|
||||
trace_stream.set_stream(is_trace_test ? &stdout : &trace_stream_ostream);
|
||||
trace_stream.set_allowed_phases({ProgramPhase::All});
|
||||
trace_stream.set_allowed_file_contexts({FileContext::Main});
|
||||
}
|
||||
|
||||
// Set the location of the prelude.
|
||||
|
||||
@@ -165,10 +165,14 @@ class Action {
|
||||
scope_ = std::move(scope);
|
||||
}
|
||||
|
||||
auto source_loc() -> std::optional<SourceLocation> { return source_loc_; }
|
||||
|
||||
protected:
|
||||
// Constructs an Action. `kind` must be the enumerator corresponding to the
|
||||
// most-derived type being constructed.
|
||||
explicit Action(Kind kind) : kind_(kind) {}
|
||||
explicit Action(std::optional<SourceLocation> source_loc, Kind kind)
|
||||
: source_loc_(source_loc), kind_(kind) {}
|
||||
std::optional<SourceLocation> source_loc_;
|
||||
|
||||
private:
|
||||
int pos_ = 0;
|
||||
@@ -183,7 +187,8 @@ class Action {
|
||||
class LocationAction : public Action {
|
||||
public:
|
||||
explicit LocationAction(Nonnull<const Expression*> expression)
|
||||
: Action(Kind::LocationAction), expression_(expression) {}
|
||||
: Action(expression->source_loc(), Kind::LocationAction),
|
||||
expression_(expression) {}
|
||||
|
||||
static auto classof(const Action* action) -> bool {
|
||||
return action->kind() == Kind::LocationAction;
|
||||
@@ -202,7 +207,7 @@ class ExpressionAction : public Action {
|
||||
explicit ExpressionAction(
|
||||
Nonnull<const Expression*> expression,
|
||||
std::optional<AllocationId> initialized_location = std::nullopt)
|
||||
: Action(Kind::ExpressionAction),
|
||||
: Action(expression->source_loc(), Kind::ExpressionAction),
|
||||
expression_(expression),
|
||||
location_received_(initialized_location) {}
|
||||
|
||||
@@ -229,7 +234,7 @@ class TypeInstantiationAction : public Action {
|
||||
public:
|
||||
explicit TypeInstantiationAction(Nonnull<const Value*> type,
|
||||
SourceLocation source_loc)
|
||||
: Action(Kind::TypeInstantiationAction),
|
||||
: Action(source_loc, Kind::TypeInstantiationAction),
|
||||
type_(type),
|
||||
source_loc_(source_loc) {}
|
||||
|
||||
@@ -249,13 +254,19 @@ class TypeInstantiationAction : public Action {
|
||||
// local context.
|
||||
class WitnessAction : public Action {
|
||||
public:
|
||||
explicit WitnessAction(Nonnull<const Witness*> witness)
|
||||
: Action(Kind::WitnessAction), witness_(witness) {}
|
||||
explicit WitnessAction(Nonnull<const Witness*> witness,
|
||||
SourceLocation source_loc)
|
||||
: Action(source_loc, Kind::WitnessAction), witness_(witness) {}
|
||||
|
||||
static auto classof(const Action* action) -> bool {
|
||||
return action->kind() == Kind::WitnessAction;
|
||||
}
|
||||
|
||||
auto source_loc() -> SourceLocation {
|
||||
CARBON_CHECK(source_loc_);
|
||||
return *source_loc_;
|
||||
}
|
||||
|
||||
// The Witness this Action resolves.
|
||||
auto witness() const -> Nonnull<const Witness*> { return witness_; }
|
||||
|
||||
@@ -269,7 +280,7 @@ class StatementAction : public Action {
|
||||
public:
|
||||
explicit StatementAction(Nonnull<const Statement*> statement,
|
||||
std::optional<AllocationId> location_received)
|
||||
: Action(Kind::StatementAction),
|
||||
: Action(statement->source_loc(), Kind::StatementAction),
|
||||
statement_(statement),
|
||||
location_received_(location_received) {}
|
||||
|
||||
@@ -306,7 +317,8 @@ class StatementAction : public Action {
|
||||
class DeclarationAction : public Action {
|
||||
public:
|
||||
explicit DeclarationAction(Nonnull<const Declaration*> declaration)
|
||||
: Action(Kind::DeclarationAction), declaration_(declaration) {}
|
||||
: Action(declaration->source_loc(), Kind::DeclarationAction),
|
||||
declaration_(declaration) {}
|
||||
|
||||
static auto classof(const Action* action) -> bool {
|
||||
return action->kind() == Kind::DeclarationAction;
|
||||
@@ -323,7 +335,7 @@ class DeclarationAction : public Action {
|
||||
class CleanUpAction : public Action {
|
||||
public:
|
||||
explicit CleanUpAction(RuntimeScope scope)
|
||||
: Action(Kind::CleanUpAction),
|
||||
: Action(std::nullopt, Kind::CleanUpAction),
|
||||
allocations_count_(scope.allocations().size()) {
|
||||
StartScope(std::move(scope));
|
||||
}
|
||||
@@ -350,7 +362,9 @@ class DestroyAction : public Action {
|
||||
// and the value is the member of the class
|
||||
explicit DestroyAction(Nonnull<const LocationValue*> location,
|
||||
Nonnull<const Value*> value)
|
||||
: Action(Kind::DestroyAction), location_(location), value_(value) {}
|
||||
: Action(std::nullopt, Kind::DestroyAction),
|
||||
location_(location),
|
||||
value_(value) {}
|
||||
|
||||
static auto classof(const Action* action) -> bool {
|
||||
return action->kind() == Kind::DestroyAction;
|
||||
@@ -371,7 +385,8 @@ class DestroyAction : public Action {
|
||||
// with AST nodes.
|
||||
class ScopeAction : public Action {
|
||||
public:
|
||||
explicit ScopeAction(RuntimeScope scope) : Action(Kind::ScopeAction) {
|
||||
explicit ScopeAction(RuntimeScope scope)
|
||||
: Action(std::nullopt, Kind::ScopeAction) {
|
||||
StartScope(std::move(scope));
|
||||
}
|
||||
|
||||
@@ -390,7 +405,7 @@ class ScopeAction : public Action {
|
||||
// Should be avoided where possible.
|
||||
class RecursiveAction : public Action {
|
||||
public:
|
||||
explicit RecursiveAction() : Action(Kind::RecursiveAction) {}
|
||||
explicit RecursiveAction() : Action(std::nullopt, Kind::RecursiveAction) {}
|
||||
|
||||
static auto classof(const Action* action) -> bool {
|
||||
return action->kind() == Kind::RecursiveAction;
|
||||
|
||||
@@ -24,6 +24,7 @@ auto AnalyzeProgram(Nonnull<Arena*> arena, AST ast,
|
||||
Nonnull<TraceStream*> trace_stream,
|
||||
Nonnull<llvm::raw_ostream*> print_stream) -> ErrorOr<AST> {
|
||||
SetProgramPhase set_prog_phase(*trace_stream, ProgramPhase::SourceProgram);
|
||||
SetFileContext set_file_ctx(*trace_stream, std::nullopt);
|
||||
|
||||
if (trace_stream->is_enabled()) {
|
||||
*trace_stream << "********** source program **********\n";
|
||||
@@ -68,9 +69,11 @@ auto AnalyzeProgram(Nonnull<Arena*> arena, AST ast,
|
||||
set_prog_phase.update_phase(ProgramPhase::Declarations);
|
||||
if (trace_stream->is_enabled()) {
|
||||
*trace_stream << "********** printing declarations **********\n";
|
||||
for (int i = ast.num_prelude_declarations;
|
||||
i < static_cast<int>(ast.declarations.size()); ++i) {
|
||||
*trace_stream << *ast.declarations[i];
|
||||
for (auto& declaration : ast.declarations) {
|
||||
set_file_ctx.update_source_loc(declaration->source_loc());
|
||||
if (trace_stream->is_enabled()) {
|
||||
*trace_stream << *declaration;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ast;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "explorer/common/arena.h"
|
||||
#include "explorer/common/error_builders.h"
|
||||
#include "explorer/common/source_location.h"
|
||||
#include "explorer/common/trace_stream.h"
|
||||
#include "explorer/interpreter/action.h"
|
||||
#include "explorer/interpreter/action_stack.h"
|
||||
#include "explorer/interpreter/stack.h"
|
||||
@@ -163,7 +164,8 @@ class Interpreter {
|
||||
|
||||
// Instantiate a witness by replacing all type variables and impl binding
|
||||
// references that occur within it by the current values of those variables.
|
||||
auto InstantiateWitness(Nonnull<const Witness*> witness)
|
||||
auto InstantiateWitness(Nonnull<const Witness*> witness,
|
||||
SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Witness*>>;
|
||||
|
||||
// Call the function `fun` with the given `arg` and the `witnesses`
|
||||
@@ -631,9 +633,9 @@ auto Interpreter::StepLocation() -> ErrorOr<Success> {
|
||||
auto Interpreter::EvalRecursively(std::unique_ptr<Action> action)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "--- recursive eval\n";
|
||||
TraceState();
|
||||
}
|
||||
|
||||
todo_.BeginRecursiveAction();
|
||||
CARBON_RETURN_IF_ERROR(todo_.Spawn(std::move(action)));
|
||||
// Note that the only `RecursiveAction` we can encounter here is our own --
|
||||
@@ -661,7 +663,7 @@ auto Interpreter::EvalAssociatedConstant(
|
||||
CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> interface,
|
||||
InstantiateType(&assoc->interface(), source_loc));
|
||||
CARBON_ASSIGN_OR_RETURN(Nonnull<const Witness*> witness,
|
||||
InstantiateWitness(&assoc->witness()));
|
||||
InstantiateWitness(&assoc->witness(), source_loc));
|
||||
|
||||
const auto* impl_witness = dyn_cast<ImplWitness>(witness);
|
||||
if (!impl_witness) {
|
||||
@@ -753,8 +755,8 @@ auto Interpreter::InstantiateBindings(Nonnull<const Bindings*> bindings,
|
||||
|
||||
ImplWitnessMap witnesses = bindings->witnesses();
|
||||
for (auto& [bind, witness] : witnesses) {
|
||||
CARBON_ASSIGN_OR_RETURN(witness,
|
||||
InstantiateWitness(cast<Witness>(witness)));
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
witness, InstantiateWitness(cast<Witness>(witness), source_loc));
|
||||
}
|
||||
|
||||
if (args == bindings->args() && witnesses == bindings->witnesses()) {
|
||||
@@ -763,11 +765,12 @@ auto Interpreter::InstantiateBindings(Nonnull<const Bindings*> bindings,
|
||||
return arena_->New<Bindings>(std::move(args), std::move(witnesses));
|
||||
}
|
||||
|
||||
auto Interpreter::InstantiateWitness(Nonnull<const Witness*> witness)
|
||||
auto Interpreter::InstantiateWitness(Nonnull<const Witness*> witness,
|
||||
SourceLocation source_loc)
|
||||
-> ErrorOr<Nonnull<const Witness*>> {
|
||||
CARBON_ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> value,
|
||||
EvalRecursively(std::make_unique<WitnessAction>(witness)));
|
||||
EvalRecursively(std::make_unique<WitnessAction>(witness, source_loc)));
|
||||
return cast<Witness>(value);
|
||||
}
|
||||
|
||||
@@ -1406,8 +1409,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
// Next, if we're accessing an interface member, evaluate the `impl`
|
||||
// expression to find the corresponding witness.
|
||||
if (impl_has_value) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(access.impl().value()));
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(
|
||||
access.impl().value(), access.source_loc()));
|
||||
} else {
|
||||
return todo_.RunAgain();
|
||||
}
|
||||
@@ -1504,8 +1507,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
if (impl_has_value) {
|
||||
// Next, if we're accessing an interface member, evaluate the
|
||||
// `impl` expression to find the corresponding witness.
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(access.impl().value()));
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(
|
||||
access.impl().value(), access.source_loc()));
|
||||
} else {
|
||||
return todo_.RunAgain();
|
||||
}
|
||||
@@ -1648,8 +1651,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
act.pos() < 2 + static_cast<int>(num_witnesses)) {
|
||||
auto iter = call.witnesses().begin();
|
||||
std::advance(iter, act.pos() - 2);
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(cast<Witness>(iter->second)));
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(
|
||||
cast<Witness>(iter->second), call.source_loc()));
|
||||
} else if (act.pos() == 2 + static_cast<int>(num_witnesses)) {
|
||||
// { { v2 :: v1([]) :: C, E, F} :: S, H}
|
||||
// -> { {C',E',F'} :: {C, E, F} :: S, H}
|
||||
@@ -2011,8 +2014,8 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
}
|
||||
|
||||
auto Interpreter::StepWitness() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Witness* witness = cast<WitnessAction>(act).witness();
|
||||
auto& act = cast<WitnessAction>(todo_.CurrentAction());
|
||||
const Witness* witness = act.witness();
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "--- step witness " << *witness << " ." << act.pos()
|
||||
<< ". --->\n";
|
||||
@@ -2036,8 +2039,8 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
|
||||
llvm::ArrayRef<Nonnull<const Witness*>> witnesses =
|
||||
cast<ConstraintWitness>(witness)->witnesses();
|
||||
if (act.pos() < static_cast<int>(witnesses.size())) {
|
||||
return todo_.Spawn(
|
||||
std::make_unique<WitnessAction>(witnesses[act.pos()]));
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(witnesses[act.pos()],
|
||||
act.source_loc()));
|
||||
}
|
||||
std::vector<Nonnull<const Witness*>> new_witnesses;
|
||||
new_witnesses.reserve(witnesses.size());
|
||||
@@ -2052,7 +2055,7 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
|
||||
const auto* constraint_impl = cast<ConstraintImplWitness>(witness);
|
||||
if (act.pos() == 0) {
|
||||
return todo_.Spawn(std::make_unique<WitnessAction>(
|
||||
constraint_impl->constraint_witness()));
|
||||
constraint_impl->constraint_witness(), act.source_loc()));
|
||||
}
|
||||
return todo_.FinishAction(ConstraintImplWitness::Make(
|
||||
arena_, cast<Witness>(act.results()[0]), constraint_impl->index()));
|
||||
@@ -2670,7 +2673,10 @@ auto InterpProgram(const AST& ast, Nonnull<Arena*> arena,
|
||||
*trace_stream << "********** initializing globals **********\n";
|
||||
}
|
||||
|
||||
SetFileContext set_file_ctx(*trace_stream,
|
||||
ast.declarations.front()->source_loc());
|
||||
for (Nonnull<Declaration*> declaration : ast.declarations) {
|
||||
set_file_ctx.update_source_loc(declaration->source_loc());
|
||||
CARBON_RETURN_IF_ERROR(interpreter.RunAllSteps(
|
||||
std::make_unique<DeclarationAction>(declaration)));
|
||||
}
|
||||
@@ -2679,6 +2685,8 @@ auto InterpProgram(const AST& ast, Nonnull<Arena*> arena,
|
||||
*trace_stream << "********** calling main function **********\n";
|
||||
}
|
||||
|
||||
CARBON_CHECK(ast.main_call);
|
||||
set_file_ctx.update_source_loc(ast.main_call.value()->source_loc());
|
||||
CARBON_RETURN_IF_ERROR(interpreter.RunAllSteps(
|
||||
std::make_unique<ExpressionAction>(*ast.main_call)));
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "explorer/common/error_builders.h"
|
||||
#include "explorer/common/nonnull.h"
|
||||
#include "explorer/common/source_location.h"
|
||||
#include "explorer/common/trace_stream.h"
|
||||
#include "explorer/interpreter/impl_scope.h"
|
||||
#include "explorer/interpreter/interpreter.h"
|
||||
#include "explorer/interpreter/pattern_analysis.h"
|
||||
@@ -1022,6 +1023,7 @@ auto TypeChecker::ImplicitlyConvert(std::string_view context,
|
||||
ConvertToConstraintType(source->source_loc(), "implicit conversion",
|
||||
destination));
|
||||
destination = destination_constraint;
|
||||
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "converting type " << *converted_value
|
||||
<< " to constraint " << *destination_constraint << " for "
|
||||
@@ -6326,23 +6328,15 @@ auto TypeChecker::DeclareAliasDeclaration(Nonnull<AliasDeclaration*> alias,
|
||||
auto TypeChecker::TypeCheck(AST& ast) -> ErrorOr<Success> {
|
||||
ImplScope impl_scope;
|
||||
ScopeInfo top_level_scope_info = ScopeInfo::ForNonClassScope(&impl_scope);
|
||||
SetFileContext set_file_ctx(*trace_stream_, std::nullopt);
|
||||
|
||||
// Track that `impl_scope` is the top-level `ImplScope`.
|
||||
llvm::SaveAndRestore<decltype(top_level_impl_scope_)>
|
||||
set_top_level_impl_scope(top_level_impl_scope_, &impl_scope);
|
||||
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "Omitting prelude type checking traces...\n";
|
||||
trace_stream_->set_in_prelude(true);
|
||||
}
|
||||
for (int i = 0; i < static_cast<int>(ast.declarations.size()); ++i) {
|
||||
if (i == ast.num_prelude_declarations) {
|
||||
trace_stream_->set_in_prelude(false);
|
||||
if (trace_stream_->is_enabled()) {
|
||||
*trace_stream_ << "Finished prelude, resuming traces...\n";
|
||||
}
|
||||
}
|
||||
auto* declaration = ast.declarations[i];
|
||||
set_file_ctx.update_source_loc(declaration->source_loc());
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
DeclareDeclaration(declaration, top_level_scope_info));
|
||||
CARBON_RETURN_IF_ERROR(
|
||||
|
||||
@@ -6,17 +6,17 @@
|
||||
// sanity checking on --parser_debug --trace_file=- along with filter flags output.
|
||||
//
|
||||
// NOAUTOUPDATE
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=execution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=source_program | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=name_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=control_flow_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=type_checking | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=unformed_variables_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=declarations | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=timing | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NAMES,NO-PRELUDE,FLOW,TYPE,UNFORMED,DECLS,EXEC,TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=source_program,declarations | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=execution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=source_program | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=name_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=control_flow_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=type_checking | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=unformed_variables_resolution | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,UNFORMED,NO-DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=declarations | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=timing | %{FileCheck-allow-unmatched} --check-prefixes=NO-SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,NO-DECLS,NO-EXEC,TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=all | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NAMES,NO-PRELUDE,FLOW,TYPE,UNFORMED,DECLS,EXEC,TIMING
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_file_context=all -trace_phase=source_program,declarations | %{FileCheck-allow-unmatched} --check-prefixes=SOURCE,NO-NAMES,NO-PRELUDE,NO-FLOW,NO-TYPE,NO-UNFORMED,DECLS,NO-EXEC,NO-TIMING
|
||||
// NO-SOURCE-NOT:STDOUT: ********** source program **********
|
||||
// SOURCE:STDOUT: ********** source program **********
|
||||
// NO-SOURCE-NOT:STDOUT: interface TestInterface {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
// A lot of output is elided: this is only checking for a few things for simple
|
||||
// sanity checking on --parser_debug --trace_file=- along with file context
|
||||
// filter flags output.
|
||||
//
|
||||
// NOAUTOUPDATE
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=main | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,NO-PRELUDE
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=prelude | %{FileCheck-allow-unmatched} --check-prefixes=NO-MAIN,PRELUDE
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=all | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,PRELUDE
|
||||
// RUN: %{explorer} --parser_debug --trace_file=- -trace_phase=all -trace_file_context=main,prelude | %{FileCheck-allow-unmatched} --check-prefixes=MAIN,PRELUDE
|
||||
// NO-PRELUDE-NOT:STDOUT: ** declaring interface As
|
||||
// PRELUDE:STDOUT: ** declaring interface As
|
||||
// NO-MAIN-NOT:STDOUT: ** declaring function Main
|
||||
// MAIN:STDOUT: ** declaring function Main
|
||||
// NO-PRELUDE-NOT:STDOUT: interface As {
|
||||
// PRELUDE:STDOUT: interface As {
|
||||
// NO-MAIN-NOT:STDOUT: fn Main ()-> i32 {
|
||||
// MAIN:STDOUT: fn Main ()-> i32 {
|
||||
// NO-MAIN-NOT:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
|
||||
// MAIN:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
|
||||
|
||||
package ExplorerTest api;
|
||||
|
||||
interface TestInterface {}
|
||||
|
||||
fn Main() -> i32 {
|
||||
return 0;
|
||||
}
|
||||
@@ -81,6 +81,22 @@ auto ExplorerMain(int argc, char** argv, void* static_for_main_addr,
|
||||
"Include trace output for all phases.")),
|
||||
cl::CommaSeparated);
|
||||
|
||||
cl::list<FileContext> allowed_file_contexts(
|
||||
"trace_file_context",
|
||||
cl::desc("Select file contexts for which you want to include the trace "
|
||||
"output"),
|
||||
cl::values(
|
||||
clEnumValN(
|
||||
FileContext::Main, "main",
|
||||
"Include trace output for file containing the main function"),
|
||||
clEnumValN(FileContext::Prelude, "prelude",
|
||||
"Include trace output for prelude"),
|
||||
clEnumValN(FileContext::Import, "import",
|
||||
"Include trace output for imports"),
|
||||
clEnumValN(FileContext::All, "all",
|
||||
"Include trace output for all files")),
|
||||
cl::CommaSeparated);
|
||||
|
||||
// Use the executable path as a base for the relative prelude path.
|
||||
std::string exe =
|
||||
llvm::sys::fs::getMainExecutable(argv[0], static_for_main_addr);
|
||||
@@ -102,6 +118,7 @@ auto ExplorerMain(int argc, char** argv, void* static_for_main_addr,
|
||||
if (!trace_file_name.empty()) {
|
||||
// Adding allowed phases in the trace_stream
|
||||
trace_stream.set_allowed_phases(allowed_program_phases);
|
||||
trace_stream.set_allowed_file_contexts(allowed_file_contexts);
|
||||
if (trace_file_name == "-") {
|
||||
trace_stream.set_stream(&llvm::outs());
|
||||
} else {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user