mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Add the ability to pipe trace output to a file. (#1183)
Breaks `--trace` into two flags: - `--parser_debug`, which sets the parser debug level (which I haven't dug into piping with `--trace`, but seemed likely to be troublesome) - `--trace_file`, which now the type checker and interpreter will use for trace information (note compile errors should use a different channel) Most of the file edits are just mechanical testdata flag updates: `sed -i 's/--trace/--parser_debug --trace_file=-/' testdata/**/*.carbon` To explain the output paths: - parse/compile errors: stderr - print() calls: stdout - parser tracing: `--parser_debug` option, stdout (formerly stdout if `--trace`) - type check/compile tracing: `--trace_file=<file>`, giving `-` uses stdout (formerly stdout if `--trace`) - return code of executed Carbon code: `--trace_file` if set, stdout if not (formerly stdout always)
This commit is contained in:
@@ -17,11 +17,13 @@
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
auto ExecProgram(Nonnull<Arena*> arena, AST ast, bool trace) -> ErrorOr<int> {
|
||||
if (trace) {
|
||||
llvm::outs() << "********** source program **********\n";
|
||||
auto ExecProgram(Nonnull<Arena*> arena, AST ast,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<int> {
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** source program **********\n";
|
||||
for (const auto decl : ast.declarations) {
|
||||
llvm::outs() << *decl;
|
||||
**trace_stream << *decl;
|
||||
}
|
||||
}
|
||||
SourceLocation source_loc("<Main()>", 0);
|
||||
@@ -30,29 +32,27 @@ auto ExecProgram(Nonnull<Arena*> arena, AST ast, bool trace) -> ErrorOr<int> {
|
||||
arena->New<TupleLiteral>(source_loc));
|
||||
// Although name resolution is currently done once, generic programming
|
||||
// (particularly templates) may require more passes.
|
||||
if (trace) {
|
||||
llvm::outs() << "********** resolving names **********\n";
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** resolving names **********\n";
|
||||
}
|
||||
RETURN_IF_ERROR(ResolveNames(ast));
|
||||
if (trace) {
|
||||
llvm::outs() << "********** resolving control flow **********\n";
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** resolving control flow **********\n";
|
||||
}
|
||||
RETURN_IF_ERROR(ResolveControlFlow(ast));
|
||||
if (trace) {
|
||||
llvm::outs() << "********** type checking **********\n";
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** type checking **********\n";
|
||||
}
|
||||
RETURN_IF_ERROR(TypeChecker(arena, trace).TypeCheck(ast));
|
||||
if (trace) {
|
||||
llvm::outs() << "\n";
|
||||
llvm::outs() << "********** type checking complete **********\n";
|
||||
RETURN_IF_ERROR(TypeChecker(arena, trace_stream).TypeCheck(ast));
|
||||
if (trace_stream) {
|
||||
**trace_stream << "\n";
|
||||
**trace_stream << "********** type checking complete **********\n";
|
||||
for (const auto decl : ast.declarations) {
|
||||
llvm::outs() << *decl;
|
||||
**trace_stream << *decl;
|
||||
}
|
||||
llvm::outs() << "********** starting execution **********\n";
|
||||
**trace_stream << "********** starting execution **********\n";
|
||||
}
|
||||
ASSIGN_OR_RETURN(const int result, InterpProgram(ast, arena, trace));
|
||||
llvm::outs() << "result: " << result << "\n";
|
||||
return result;
|
||||
return InterpProgram(ast, arena, trace_stream);
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -10,11 +10,14 @@
|
||||
#define EXECUTABLE_SEMANTICS_INTERPRETER_EXEC_PROGRAM_H_
|
||||
|
||||
#include "executable_semantics/ast/ast.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace Carbon {
|
||||
|
||||
// Runs the top-level declaration list.
|
||||
auto ExecProgram(Nonnull<Arena*> arena, AST ast, bool trace) -> ErrorOr<int>;
|
||||
auto ExecProgram(Nonnull<Arena*> arena, AST ast,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<int>;
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
|
||||
@@ -47,11 +47,12 @@ class Interpreter {
|
||||
// Constructs an Interpreter which allocates values on `arena`, and prints
|
||||
// traces if `trace` is true. `phase` indicates whether it executes at
|
||||
// compile time or run time.
|
||||
Interpreter(Phase phase, Nonnull<Arena*> arena, bool trace)
|
||||
Interpreter(Phase phase, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
: arena_(arena),
|
||||
heap_(arena),
|
||||
todo_(MakeTodo(phase, &heap_)),
|
||||
trace_(trace),
|
||||
trace_stream_(trace_stream),
|
||||
phase_(phase) {}
|
||||
|
||||
~Interpreter();
|
||||
@@ -117,7 +118,7 @@ class Interpreter {
|
||||
// contents of any non-completed continuations at the end of execution.
|
||||
std::vector<Nonnull<ContinuationValue::StackFragment*>> stack_fragments_;
|
||||
|
||||
bool trace_;
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream_;
|
||||
Phase phase_;
|
||||
};
|
||||
|
||||
@@ -283,9 +284,9 @@ auto PatternMatch(Nonnull<const Value*> p, Nonnull<const Value*> v,
|
||||
auto Interpreter::StepLvalue() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Expression& exp = cast<LValAction>(act).expression();
|
||||
if (trace_) {
|
||||
llvm::outs() << "--- step lvalue " << exp << " (" << exp.source_loc()
|
||||
<< ") --->\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- step lvalue " << exp << " (" << exp.source_loc()
|
||||
<< ") --->\n";
|
||||
}
|
||||
switch (exp.kind()) {
|
||||
case ExpressionKind::IdentifierExpression: {
|
||||
@@ -373,13 +374,13 @@ auto Interpreter::StepLvalue() -> ErrorOr<Success> {
|
||||
auto Interpreter::InstantiateType(Nonnull<const Value*> type,
|
||||
SourceLocation source_loc) const
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "instantiating: " << *type << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "instantiating: " << *type << "\n";
|
||||
}
|
||||
switch (type->kind()) {
|
||||
case Value::Kind::VariableType: {
|
||||
if (trace_) {
|
||||
llvm::outs() << "case VariableType\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "case VariableType\n";
|
||||
}
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> value,
|
||||
@@ -390,8 +391,8 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
|
||||
return value;
|
||||
}
|
||||
case Value::Kind::NominalClassType: {
|
||||
if (trace_) {
|
||||
llvm::outs() << "case NominalClassType\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "case NominalClassType\n";
|
||||
}
|
||||
const auto& class_type = cast<NominalClassType>(*type);
|
||||
BindingMap inst_type_args;
|
||||
@@ -399,15 +400,15 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
|
||||
ASSIGN_OR_RETURN(inst_type_args[ty_var],
|
||||
InstantiateType(ty_arg, source_loc));
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "finished instantiating ty_arg\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "finished instantiating ty_arg\n";
|
||||
}
|
||||
std::map<Nonnull<const ImplBinding*>, Nonnull<const Witness*>> witnesses;
|
||||
for (const auto& [bind, impl] : class_type.impls()) {
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> witness_addr,
|
||||
todo_.ValueOfNode(impl, source_loc));
|
||||
if (trace_) {
|
||||
llvm::outs() << "witness_addr: " << *witness_addr << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "witness_addr: " << *witness_addr << "\n";
|
||||
}
|
||||
// If the witness came directly from an `impl` declaration (via
|
||||
// `constant_value`), then it is a `Witness`. If the witness
|
||||
@@ -428,8 +429,8 @@ auto Interpreter::InstantiateType(Nonnull<const Value*> type,
|
||||
}
|
||||
witnesses[bind] = witness;
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "finished finding witnesses\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "finished finding witnesses\n";
|
||||
}
|
||||
return arena_->New<NominalClassType>(&class_type.declaration(),
|
||||
inst_type_args, witnesses);
|
||||
@@ -540,9 +541,9 @@ auto Interpreter::Convert(Nonnull<const Value*> value,
|
||||
auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Expression& exp = cast<ExpressionAction>(act).expression();
|
||||
if (trace_) {
|
||||
llvm::outs() << "--- step exp " << exp << " (" << exp.source_loc()
|
||||
<< ") --->\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- step exp " << exp << " (" << exp.source_loc()
|
||||
<< ") --->\n";
|
||||
}
|
||||
switch (exp.kind()) {
|
||||
case ExpressionKind::IndexExpression: {
|
||||
@@ -697,8 +698,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
const FunctionValue& fun_val =
|
||||
cast<FunctionValue>(*act.results()[0]);
|
||||
const FunctionDeclaration& function = fun_val.declaration();
|
||||
if (trace_) {
|
||||
llvm::outs() << "*** call function " << function.name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "*** call function " << function.name()
|
||||
<< "\n";
|
||||
}
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> converted_args,
|
||||
Convert(act.results()[1],
|
||||
@@ -920,9 +922,9 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
|
||||
auto Interpreter::StepPattern() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Pattern& pattern = cast<PatternAction>(act).pattern();
|
||||
if (trace_) {
|
||||
llvm::outs() << "--- step pattern " << pattern << " ("
|
||||
<< pattern.source_loc() << ") --->\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- step pattern " << pattern << " ("
|
||||
<< pattern.source_loc() << ") --->\n";
|
||||
}
|
||||
switch (pattern.kind()) {
|
||||
case PatternKind::AutoPattern: {
|
||||
@@ -991,10 +993,10 @@ auto Interpreter::StepPattern() -> ErrorOr<Success> {
|
||||
auto Interpreter::StepStmt() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Statement& stmt = cast<StatementAction>(act).statement();
|
||||
if (trace_) {
|
||||
llvm::outs() << "--- step stmt ";
|
||||
stmt.PrintDepth(1, llvm::outs());
|
||||
llvm::outs() << " (" << stmt.source_loc() << ") --->\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- step stmt ";
|
||||
stmt.PrintDepth(1, **trace_stream_);
|
||||
**trace_stream_ << " (" << stmt.source_loc() << ") --->\n";
|
||||
}
|
||||
switch (stmt.kind()) {
|
||||
case StatementKind::Match: {
|
||||
@@ -1211,8 +1213,9 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
|
||||
auto Interpreter::StepDeclaration() -> ErrorOr<Success> {
|
||||
Action& act = todo_.CurrentAction();
|
||||
const Declaration& decl = cast<DeclarationAction>(act).declaration();
|
||||
if (trace_) {
|
||||
llvm::outs() << "--- step declaration (" << decl.source_loc() << ") --->\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "--- step declaration (" << decl.source_loc()
|
||||
<< ") --->\n";
|
||||
}
|
||||
switch (decl.kind()) {
|
||||
case DeclarationKind::VariableDeclaration: {
|
||||
@@ -1266,24 +1269,25 @@ auto Interpreter::Step() -> ErrorOr<Success> {
|
||||
|
||||
auto Interpreter::RunAllSteps(std::unique_ptr<Action> action)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
PrintState(llvm::outs());
|
||||
if (trace_stream_) {
|
||||
PrintState(**trace_stream_);
|
||||
}
|
||||
todo_.Start(std::move(action));
|
||||
while (!todo_.IsEmpty()) {
|
||||
RETURN_IF_ERROR(Step());
|
||||
if (trace_) {
|
||||
PrintState(llvm::outs());
|
||||
if (trace_stream_) {
|
||||
PrintState(**trace_stream_);
|
||||
}
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
|
||||
auto InterpProgram(const AST& ast, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpProgram(const AST& ast, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<int> {
|
||||
Interpreter interpreter(Phase::RunTime, arena, trace);
|
||||
if (trace) {
|
||||
llvm::outs() << "********** initializing globals **********\n";
|
||||
Interpreter interpreter(Phase::RunTime, arena, trace_stream);
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** initializing globals **********\n";
|
||||
}
|
||||
|
||||
for (Nonnull<Declaration*> declaration : ast.declarations) {
|
||||
@@ -1291,8 +1295,8 @@ auto InterpProgram(const AST& ast, Nonnull<Arena*> arena, bool trace)
|
||||
std::make_unique<DeclarationAction>(declaration)));
|
||||
}
|
||||
|
||||
if (trace) {
|
||||
llvm::outs() << "********** calling main function **********\n";
|
||||
if (trace_stream) {
|
||||
**trace_stream << "********** calling main function **********\n";
|
||||
}
|
||||
|
||||
RETURN_IF_ERROR(interpreter.RunAllSteps(
|
||||
@@ -1301,17 +1305,19 @@ auto InterpProgram(const AST& ast, Nonnull<Arena*> arena, bool trace)
|
||||
return cast<IntValue>(*interpreter.result()).value();
|
||||
}
|
||||
|
||||
auto InterpExp(Nonnull<const Expression*> e, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpExp(Nonnull<const Expression*> e, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
Interpreter interpreter(Phase::CompileTime, arena, trace);
|
||||
Interpreter interpreter(Phase::CompileTime, arena, trace_stream);
|
||||
RETURN_IF_ERROR(
|
||||
interpreter.RunAllSteps(std::make_unique<ExpressionAction>(e)));
|
||||
return interpreter.result();
|
||||
}
|
||||
|
||||
auto InterpPattern(Nonnull<const Pattern*> p, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpPattern(Nonnull<const Pattern*> p, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<Nonnull<const Value*>> {
|
||||
Interpreter interpreter(Phase::CompileTime, arena, trace);
|
||||
Interpreter interpreter(Phase::CompileTime, arena, trace_stream);
|
||||
RETURN_IF_ERROR(interpreter.RunAllSteps(std::make_unique<PatternAction>(p)));
|
||||
return interpreter.result();
|
||||
}
|
||||
|
||||
@@ -23,19 +23,22 @@ namespace Carbon {
|
||||
|
||||
// Interprets the program defined by `ast`, allocating values on `arena` and
|
||||
// printing traces if `trace` is true.
|
||||
auto InterpProgram(const AST& ast, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpProgram(const AST& ast, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<int>;
|
||||
|
||||
// Interprets `e` at compile-time, allocating values on `arena` and
|
||||
// printing traces if `trace` is true. The caller must ensure that all the
|
||||
// code this evaluates has been typechecked.
|
||||
auto InterpExp(Nonnull<const Expression*> e, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpExp(Nonnull<const Expression*> e, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
// Interprets `p` at compile-time, allocating values on `arena` and
|
||||
// printing traces if `trace` is true. The caller must ensure that all the
|
||||
// code this evaluates has been typechecked.
|
||||
auto InterpPattern(Nonnull<const Pattern*> p, Nonnull<Arena*> arena, bool trace)
|
||||
auto InterpPattern(Nonnull<const Pattern*> p, Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
-> ErrorOr<Nonnull<const Value*>>;
|
||||
|
||||
// Attempts to match `v` against the pattern `p`, returning whether matching
|
||||
|
||||
@@ -432,9 +432,9 @@ auto TypeChecker::Substitute(
|
||||
}
|
||||
Nonnull<const NominalClassType*> new_class_type =
|
||||
arena_->New<NominalClassType>(&class_type.declaration(), type_args);
|
||||
if (trace_) {
|
||||
llvm::outs() << "substitution: " << class_type << " => "
|
||||
<< *new_class_type << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "substitution: " << class_type << " => "
|
||||
<< *new_class_type << "\n";
|
||||
}
|
||||
return new_class_type;
|
||||
}
|
||||
@@ -473,11 +473,11 @@ auto TypeChecker::Substitute(
|
||||
auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "checking expression " << *e;
|
||||
llvm::outs() << "\nconstants: ";
|
||||
PrintConstants(llvm::outs());
|
||||
llvm::outs() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "checking expression " << *e;
|
||||
**trace_stream_ << "\nconstants: ";
|
||||
PrintConstants(**trace_stream_);
|
||||
**trace_stream_ << "\n";
|
||||
}
|
||||
switch (e->kind()) {
|
||||
case ExpressionKind::IndexExpression: {
|
||||
@@ -492,7 +492,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
"tuple index", arena_->New<IntType>(),
|
||||
&index.offset().static_type()));
|
||||
ASSIGN_OR_RETURN(auto offset_value,
|
||||
InterpExp(&index.offset(), arena_, trace_));
|
||||
InterpExp(&index.offset(), arena_, trace_stream_));
|
||||
int i = cast<IntValue>(*offset_value).value();
|
||||
if (i < 0 || i >= static_cast<int>(tuple_type.elements().size())) {
|
||||
return CompilationError(e->source_loc())
|
||||
@@ -541,7 +541,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
for (auto& arg : struct_type.fields()) {
|
||||
RETURN_IF_ERROR(TypeCheckExp(&arg.expression(), impl_scope));
|
||||
ASSIGN_OR_RETURN(auto value,
|
||||
InterpExp(&arg.expression(), arena_, trace_));
|
||||
InterpExp(&arg.expression(), arena_, trace_stream_));
|
||||
RETURN_IF_ERROR(
|
||||
ExpectIsConcreteType(arg.expression().source_loc(), value));
|
||||
}
|
||||
@@ -690,8 +690,9 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
// If `T` is a type variable and `foo` is a class function in an
|
||||
// interface implemented by `T`, then `T.foo` accesses the `foo` class
|
||||
// function of `T`.
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> var_addr,
|
||||
InterpExp(&access.aggregate(), arena_, trace_));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> var_addr,
|
||||
InterpExp(&access.aggregate(), arena_, trace_stream_));
|
||||
const VariableType& var_type = cast<VariableType>(*var_addr);
|
||||
const InterfaceType& iface_type = cast<InterfaceType>(aggregate_type);
|
||||
const InterfaceDeclaration& iface_decl = iface_type.declaration();
|
||||
@@ -903,11 +904,12 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
.declaration();
|
||||
BindingMap generic_args;
|
||||
if (class_decl.type_params().has_value()) {
|
||||
if (trace_) {
|
||||
llvm::outs() << "pattern matching type params and args ";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "pattern matching type params and args ";
|
||||
}
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> arg,
|
||||
InterpExp(&call.argument(), arena_, trace_));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> arg,
|
||||
InterpExp(&call.argument(), arena_, trace_stream_));
|
||||
CHECK(PatternMatch(&(*class_decl.type_params())->value(), arg,
|
||||
call.source_loc(), std::nullopt, generic_args));
|
||||
} else {
|
||||
@@ -957,11 +959,11 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
case ExpressionKind::FunctionTypeLiteral: {
|
||||
auto& fn = cast<FunctionTypeLiteral>(*e);
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> param_type,
|
||||
InterpExp(&fn.parameter(), arena_, trace_));
|
||||
InterpExp(&fn.parameter(), arena_, trace_stream_));
|
||||
RETURN_IF_ERROR(
|
||||
ExpectIsConcreteType(fn.parameter().source_loc(), param_type));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> ret_type,
|
||||
InterpExp(&fn.return_type(), arena_, trace_));
|
||||
InterpExp(&fn.return_type(), arena_, trace_stream_));
|
||||
RETURN_IF_ERROR(
|
||||
ExpectIsConcreteType(fn.return_type().source_loc(), ret_type));
|
||||
fn.set_static_type(arena_->New<TypeType>());
|
||||
@@ -1022,9 +1024,9 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
auto& array_literal = cast<ArrayTypeLiteral>(*e);
|
||||
RETURN_IF_ERROR(
|
||||
TypeCheckExp(&array_literal.element_type_expression(), impl_scope));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> element_type,
|
||||
InterpExp(&array_literal.element_type_expression(), arena_, trace_));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> element_type,
|
||||
InterpExp(&array_literal.element_type_expression(),
|
||||
arena_, trace_stream_));
|
||||
RETURN_IF_ERROR(ExpectIsConcreteType(
|
||||
array_literal.element_type_expression().source_loc(), element_type));
|
||||
|
||||
@@ -1036,7 +1038,7 @@ auto TypeChecker::TypeCheckExp(Nonnull<Expression*> e,
|
||||
&array_literal.size_expression().static_type()));
|
||||
ASSIGN_OR_RETURN(
|
||||
Nonnull<const Value*> size_value,
|
||||
InterpExp(&array_literal.size_expression(), arena_, trace_));
|
||||
InterpExp(&array_literal.size_expression(), arena_, trace_stream_));
|
||||
if (cast<IntValue>(size_value)->value() < 0) {
|
||||
return CompilationError(array_literal.size_expression().source_loc())
|
||||
<< "Array size cannot be negative";
|
||||
@@ -1087,14 +1089,14 @@ auto TypeChecker::TypeCheckPattern(
|
||||
Nonnull<Pattern*> p, std::optional<Nonnull<const Value*>> expected,
|
||||
const ImplScope& impl_scope, ValueCategory enclosing_value_category)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "checking pattern " << *p;
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "checking pattern " << *p;
|
||||
if (expected) {
|
||||
llvm::outs() << ", expecting " << **expected;
|
||||
**trace_stream_ << ", expecting " << **expected;
|
||||
}
|
||||
llvm::outs() << "\nconstants: ";
|
||||
PrintConstants(llvm::outs());
|
||||
llvm::outs() << "\n";
|
||||
**trace_stream_ << "\nconstants: ";
|
||||
PrintConstants(**trace_stream_);
|
||||
**trace_stream_ << "\n";
|
||||
}
|
||||
switch (p->kind()) {
|
||||
case PatternKind::AutoPattern: {
|
||||
@@ -1110,7 +1112,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
RETURN_IF_ERROR(TypeCheckPattern(&binding.type(), std::nullopt,
|
||||
impl_scope, enclosing_value_category));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> type,
|
||||
InterpPattern(&binding.type(), arena_, trace_));
|
||||
InterpPattern(&binding.type(), arena_, trace_stream_));
|
||||
if (expected) {
|
||||
if (IsConcreteType(type)) {
|
||||
RETURN_IF_ERROR(
|
||||
@@ -1129,7 +1131,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
RETURN_IF_ERROR(ExpectIsConcreteType(binding.source_loc(), type));
|
||||
binding.set_static_type(type);
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> binding_value,
|
||||
InterpPattern(&binding, arena_, trace_));
|
||||
InterpPattern(&binding, arena_, trace_stream_));
|
||||
SetValue(&binding, binding_value);
|
||||
|
||||
if (!binding.has_value_category()) {
|
||||
@@ -1141,7 +1143,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
auto& binding = cast<GenericBinding>(*p);
|
||||
RETURN_IF_ERROR(TypeCheckExp(&binding.type(), impl_scope));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> type,
|
||||
InterpExp(&binding.type(), arena_, trace_));
|
||||
InterpExp(&binding.type(), arena_, trace_stream_));
|
||||
if (expected) {
|
||||
return CompilationError(binding.type().source_loc())
|
||||
<< "Generic binding may not occur in pattern with expected "
|
||||
@@ -1150,7 +1152,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
}
|
||||
binding.set_static_type(type);
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> val,
|
||||
InterpPattern(&binding, arena_, trace_));
|
||||
InterpPattern(&binding, arena_, trace_stream_));
|
||||
binding.set_symbolic_identity(val);
|
||||
Nonnull<ImplBinding*> impl_binding = arena_->New<ImplBinding>(
|
||||
binding.source_loc(), &binding, &binding.static_type());
|
||||
@@ -1177,14 +1179,14 @@ auto TypeChecker::TypeCheckPattern(
|
||||
}
|
||||
RETURN_IF_ERROR(TypeCheckPattern(field, expected_field_type, impl_scope,
|
||||
enclosing_value_category));
|
||||
if (trace_)
|
||||
llvm::outs() << "finished checking tuple pattern field " << *field
|
||||
<< "\n";
|
||||
if (trace_stream_)
|
||||
**trace_stream_ << "finished checking tuple pattern field " << *field
|
||||
<< "\n";
|
||||
field_types.push_back(&field->static_type());
|
||||
}
|
||||
tuple.set_static_type(arena_->New<TupleValue>(std::move(field_types)));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> tuple_value,
|
||||
InterpPattern(&tuple, arena_, trace_));
|
||||
InterpPattern(&tuple, arena_, trace_stream_));
|
||||
SetValue(&tuple, tuple_value);
|
||||
return Success();
|
||||
}
|
||||
@@ -1217,7 +1219,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
enclosing_value_category));
|
||||
alternative.set_static_type(&choice_type);
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> alternative_value,
|
||||
InterpPattern(&alternative, arena_, trace_));
|
||||
InterpPattern(&alternative, arena_, trace_stream_));
|
||||
SetValue(&alternative, alternative_value);
|
||||
return Success();
|
||||
}
|
||||
@@ -1226,7 +1228,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
RETURN_IF_ERROR(TypeCheckExp(&expression, impl_scope));
|
||||
p->set_static_type(&expression.static_type());
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> expr_value,
|
||||
InterpPattern(p, arena_, trace_));
|
||||
InterpPattern(p, arena_, trace_stream_));
|
||||
SetValue(p, expr_value);
|
||||
return Success();
|
||||
}
|
||||
@@ -1238,7 +1240,7 @@ auto TypeChecker::TypeCheckPattern(
|
||||
let_var_pattern.value_category()));
|
||||
let_var_pattern.set_static_type(&let_var_pattern.pattern().static_type());
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> pattern_value,
|
||||
InterpPattern(&let_var_pattern, arena_, trace_));
|
||||
InterpPattern(&let_var_pattern, arena_, trace_stream_));
|
||||
SetValue(&let_var_pattern, pattern_value);
|
||||
return Success();
|
||||
}
|
||||
@@ -1247,8 +1249,8 @@ auto TypeChecker::TypeCheckPattern(
|
||||
auto TypeChecker::TypeCheckStmt(Nonnull<Statement*> s,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "checking statement " << *s << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "checking statement " << *s << "\n";
|
||||
}
|
||||
switch (s->kind()) {
|
||||
case StatementKind::Match: {
|
||||
@@ -1438,15 +1440,15 @@ auto TypeChecker::ExpectReturnOnAllPaths(
|
||||
auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
const ImplScope& enclosing_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "** declaring function " << f->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** declaring function " << f->name() << "\n";
|
||||
}
|
||||
// Bring the deduced parameters into scope
|
||||
for (Nonnull<GenericBinding*> deduced : f->deduced_parameters()) {
|
||||
RETURN_IF_ERROR(TypeCheckExp(&deduced->type(), enclosing_scope));
|
||||
deduced->set_symbolic_identity(arena_->New<VariableType>(deduced));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> type_of_type,
|
||||
InterpExp(&deduced->type(), arena_, trace_));
|
||||
InterpExp(&deduced->type(), arena_, trace_stream_));
|
||||
deduced->set_static_type(type_of_type);
|
||||
}
|
||||
// Create the impl_bindings
|
||||
@@ -1486,7 +1488,7 @@ auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
// Should we be doing SetConstantValue instead? -Jeremy
|
||||
// And shouldn't the type of this be Type?
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> ret_type,
|
||||
InterpExp(*return_expression, arena_, trace_));
|
||||
InterpExp(*return_expression, arena_, trace_stream_));
|
||||
f->return_term().set_static_type(ret_type);
|
||||
} else if (f->return_term().is_omitted()) {
|
||||
f->return_term().set_static_type(TupleValue::Empty());
|
||||
@@ -1520,9 +1522,9 @@ auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
// TODO: Check that main doesn't have any parameters.
|
||||
}
|
||||
|
||||
if (trace_) {
|
||||
llvm::outs() << "** finished declaring function " << f->name()
|
||||
<< " of type " << f->static_type() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** finished declaring function " << f->name()
|
||||
<< " of type " << f->static_type() << "\n";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -1530,8 +1532,8 @@ auto TypeChecker::DeclareFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
auto TypeChecker::TypeCheckFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "** checking function " << f->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** checking function " << f->name() << "\n";
|
||||
}
|
||||
// if f->return_term().is_auto(), the function body was already
|
||||
// type checked in DeclareFunctionDeclaration
|
||||
@@ -1546,15 +1548,15 @@ auto TypeChecker::TypeCheckFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
*impl_binding->type_var()->symbolic_identity(),
|
||||
impl_binding);
|
||||
}
|
||||
if (trace_)
|
||||
llvm::outs() << function_scope;
|
||||
if (trace_stream_)
|
||||
**trace_stream_ << function_scope;
|
||||
RETURN_IF_ERROR(TypeCheckStmt(*f->body(), function_scope));
|
||||
if (!f->return_term().is_omitted()) {
|
||||
RETURN_IF_ERROR(ExpectReturnOnAllPaths(f->body(), f->source_loc()));
|
||||
}
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "** finished checking function " << f->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** finished checking function " << f->name() << "\n";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -1562,8 +1564,8 @@ auto TypeChecker::TypeCheckFunctionDeclaration(Nonnull<FunctionDeclaration*> f,
|
||||
auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
||||
ImplScope& enclosing_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "** declaring class " << class_decl->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** declaring class " << class_decl->name() << "\n";
|
||||
}
|
||||
if (class_decl->type_params().has_value()) {
|
||||
ImplScope class_scope;
|
||||
@@ -1571,8 +1573,8 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
||||
RETURN_IF_ERROR(TypeCheckPattern(*class_decl->type_params(), std::nullopt,
|
||||
class_scope, ValueCategory::Let));
|
||||
AddPatternImpls(*class_decl->type_params(), class_scope);
|
||||
if (trace_) {
|
||||
llvm::outs() << class_scope;
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << class_scope;
|
||||
}
|
||||
|
||||
Nonnull<NominalClassType*> class_type =
|
||||
@@ -1598,9 +1600,9 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
||||
RETURN_IF_ERROR(DeclareDeclaration(m, enclosing_scope));
|
||||
}
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "** finished declaring class " << class_decl->name()
|
||||
<< "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** finished declaring class " << class_decl->name()
|
||||
<< "\n";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -1608,22 +1610,23 @@ auto TypeChecker::DeclareClassDeclaration(Nonnull<ClassDeclaration*> class_decl,
|
||||
auto TypeChecker::TypeCheckClassDeclaration(
|
||||
Nonnull<ClassDeclaration*> class_decl, const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "** checking class " << class_decl->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** checking class " << class_decl->name() << "\n";
|
||||
}
|
||||
ImplScope class_scope;
|
||||
class_scope.AddParent(&impl_scope);
|
||||
if (class_decl->type_params().has_value()) {
|
||||
AddPatternImpls(*class_decl->type_params(), class_scope);
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << class_scope;
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << class_scope;
|
||||
}
|
||||
for (Nonnull<Declaration*> m : class_decl->members()) {
|
||||
RETURN_IF_ERROR(TypeCheckDeclaration(m, class_scope));
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "** finished checking class " << class_decl->name() << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "** finished checking class " << class_decl->name()
|
||||
<< "\n";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -1659,18 +1662,18 @@ auto TypeChecker::TypeCheckInterfaceDeclaration(
|
||||
auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
ImplScope& enclosing_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "declaring " << *impl_decl << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "declaring " << *impl_decl << "\n";
|
||||
}
|
||||
RETURN_IF_ERROR(TypeCheckExp(&impl_decl->interface(), enclosing_scope));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> iface_type,
|
||||
InterpExp(&impl_decl->interface(), arena_, trace_));
|
||||
InterpExp(&impl_decl->interface(), arena_, trace_stream_));
|
||||
const auto& iface_decl = cast<InterfaceType>(*iface_type).declaration();
|
||||
impl_decl->set_interface_type(iface_type);
|
||||
|
||||
RETURN_IF_ERROR(TypeCheckExp(impl_decl->impl_type(), enclosing_scope));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> impl_type_value,
|
||||
InterpExp(impl_decl->impl_type(), arena_, trace_));
|
||||
InterpExp(impl_decl->impl_type(), arena_, trace_stream_));
|
||||
enclosing_scope.Add(iface_type, impl_type_value, impl_decl);
|
||||
|
||||
for (Nonnull<Declaration*> m : impl_decl->members()) {
|
||||
@@ -1704,14 +1707,14 @@ auto TypeChecker::DeclareImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
auto TypeChecker::TypeCheckImplDeclaration(Nonnull<ImplDeclaration*> impl_decl,
|
||||
const ImplScope& impl_scope)
|
||||
-> ErrorOr<Success> {
|
||||
if (trace_) {
|
||||
llvm::outs() << "checking " << *impl_decl << "\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "checking " << *impl_decl << "\n";
|
||||
}
|
||||
for (Nonnull<Declaration*> m : impl_decl->members()) {
|
||||
RETURN_IF_ERROR(TypeCheckDeclaration(m, impl_scope));
|
||||
}
|
||||
if (trace_) {
|
||||
llvm::outs() << "finished checking impl\n";
|
||||
if (trace_stream_) {
|
||||
**trace_stream_ << "finished checking impl\n";
|
||||
}
|
||||
return Success();
|
||||
}
|
||||
@@ -1722,8 +1725,8 @@ auto TypeChecker::DeclareChoiceDeclaration(Nonnull<ChoiceDeclaration*> choice,
|
||||
std::vector<NamedValue> alternatives;
|
||||
for (Nonnull<AlternativeSignature*> alternative : choice->alternatives()) {
|
||||
RETURN_IF_ERROR(TypeCheckExp(&alternative->signature(), enclosing_scope));
|
||||
ASSIGN_OR_RETURN(auto signature,
|
||||
InterpExp(&alternative->signature(), arena_, trace_));
|
||||
ASSIGN_OR_RETURN(auto signature, InterpExp(&alternative->signature(),
|
||||
arena_, trace_stream_));
|
||||
alternatives.push_back({.name = alternative->name(), .value = signature});
|
||||
}
|
||||
auto ct = arena_->New<ChoiceType>(choice->name(), std::move(alternatives));
|
||||
@@ -1849,7 +1852,7 @@ auto TypeChecker::DeclareDeclaration(Nonnull<Declaration*> d,
|
||||
RETURN_IF_ERROR(TypeCheckPattern(&var.binding(), std::nullopt,
|
||||
enclosing_scope, var.value_category()));
|
||||
ASSIGN_OR_RETURN(Nonnull<const Value*> declared_type,
|
||||
InterpExp(&type, arena_, trace_));
|
||||
InterpExp(&type, arena_, trace_stream_));
|
||||
var.set_static_type(declared_type);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,9 @@ namespace Carbon {
|
||||
|
||||
class TypeChecker {
|
||||
public:
|
||||
explicit TypeChecker(Nonnull<Arena*> arena, bool trace)
|
||||
: arena_(arena), trace_(trace) {}
|
||||
explicit TypeChecker(Nonnull<Arena*> arena,
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream)
|
||||
: arena_(arena), trace_stream_(trace_stream) {}
|
||||
|
||||
// Type-checks `ast` and sets properties such as `static_type`, as documented
|
||||
// on the individual nodes.
|
||||
@@ -176,7 +177,7 @@ class TypeChecker {
|
||||
Nonnull<Arena*> arena_;
|
||||
std::set<ValueNodeView> constants_;
|
||||
|
||||
bool trace_;
|
||||
std::optional<Nonnull<llvm::raw_ostream*>> trace_stream_;
|
||||
};
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
Reference in New Issue
Block a user