diff --git a/explorer/interpreter/BUILD b/explorer/interpreter/BUILD index 169b46857433..914003fdb0aa 100644 --- a/explorer/interpreter/BUILD +++ b/explorer/interpreter/BUILD @@ -140,6 +140,7 @@ cc_library( "//explorer/ast", "//explorer/common:error_builders", "//explorer/common:nonnull", + "//explorer/common:trace_stream", "@llvm-project//llvm:Support", ], ) diff --git a/explorer/interpreter/exec_program.cpp b/explorer/interpreter/exec_program.cpp index 3b066a3d010c..e89380bbf36b 100644 --- a/explorer/interpreter/exec_program.cpp +++ b/explorer/interpreter/exec_program.cpp @@ -51,7 +51,7 @@ auto AnalyzeProgram(Nonnull arena, AST ast, if (trace_stream->is_enabled()) { *trace_stream << "********** resolving control flow **********\n"; } - CARBON_RETURN_IF_ERROR(ResolveControlFlow(ast)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, ast)); set_prog_phase.update_phase(ProgramPhase::TypeChecking); if (trace_stream->is_enabled()) { diff --git a/explorer/interpreter/resolve_control_flow.cpp b/explorer/interpreter/resolve_control_flow.cpp index 894038ce5ce7..2ad9e6a1c788 100644 --- a/explorer/interpreter/resolve_control_flow.cpp +++ b/explorer/interpreter/resolve_control_flow.cpp @@ -32,10 +32,13 @@ struct FunctionData { // belongs to, and that information may be updated by this call. `function` // can be nullopt if `statement` does not belong to a function body, for // example if it is part of a continuation body instead. -static auto ResolveControlFlow(Nonnull statement, +static auto ResolveControlFlow(Nonnull trace_stream, + Nonnull statement, std::optional> loop, std::optional> function) -> ErrorOr { + SetFileContext set_file_ctx(*trace_stream, statement->source_loc()); + switch (statement->kind()) { case StatementKind::ReturnVar: case StatementKind::ReturnExpression: { @@ -73,6 +76,12 @@ static auto ResolveControlFlow(Nonnull statement, } } + if (trace_stream->is_enabled()) { + *trace_stream << "--- flow-resolved return statement `" << *statement + << "` in `" << PrintAsID(*((*function)->declaration)) + << "` (" << statement->source_loc() << ")\n"; + } + return Success(); } case StatementKind::Break: @@ -81,6 +90,12 @@ static auto ResolveControlFlow(Nonnull statement, << "break is not within a loop body"; } cast(*statement).set_loop(*loop); + + if (trace_stream->is_enabled()) { + *trace_stream << "--- flow-resolved break statement `" << *statement + << "` for `" << PrintAsID(**loop) << "`\n"; + } + return Success(); case StatementKind::Continue: if (!loop.has_value()) { @@ -88,14 +103,21 @@ static auto ResolveControlFlow(Nonnull statement, << "continue is not within a loop body"; } cast(*statement).set_loop(*loop); + + if (trace_stream->is_enabled()) { + *trace_stream << "--- flow-resolved continue statement `" << *statement + << "` in `" << PrintAsID(**loop) << "` (" + << statement->source_loc() << ")\n"; + } + return Success(); case StatementKind::If: { auto& if_stmt = cast(*statement); - CARBON_RETURN_IF_ERROR( - ResolveControlFlow(&if_stmt.then_block(), loop, function)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, &if_stmt.then_block(), loop, function)); if (if_stmt.else_block().has_value()) { - CARBON_RETURN_IF_ERROR( - ResolveControlFlow(*if_stmt.else_block(), loop, function)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, *if_stmt.else_block(), loop, function)); } return Success(); } @@ -103,24 +125,38 @@ static auto ResolveControlFlow(Nonnull statement, auto& block = cast(*statement); for (auto* block_statement : block.statements()) { CARBON_RETURN_IF_ERROR( - ResolveControlFlow(block_statement, loop, function)); + ResolveControlFlow(trace_stream, block_statement, loop, function)); } return Success(); } case StatementKind::For: { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(&cast(*statement).body(), - statement, function)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, &cast(*statement).body(), statement, function)); + + if (trace_stream->is_enabled()) { + *trace_stream << "--- flow-resolved for statement `" + << PrintAsID(*statement) << "` (" + << statement->source_loc() << ")\n"; + } + return Success(); } case StatementKind::While: - CARBON_RETURN_IF_ERROR(ResolveControlFlow(&cast(*statement).body(), - statement, function)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, &cast(*statement).body(), statement, function)); + + if (trace_stream->is_enabled()) { + *trace_stream << "--- flow-resolved while statement `" + << PrintAsID(*statement) << "` (" + << statement->source_loc() << ")\n"; + } + return Success(); case StatementKind::Match: { auto& match = cast(*statement); for (Match::Clause& clause : match.clauses()) { - CARBON_RETURN_IF_ERROR( - ResolveControlFlow(&clause.statement(), loop, function)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, &clause.statement(), loop, function)); } return Success(); } @@ -132,29 +168,30 @@ static auto ResolveControlFlow(Nonnull statement, } } -auto ResolveControlFlow(Nonnull declaration) -> ErrorOr { +auto ResolveControlFlow(Nonnull trace_stream, + Nonnull declaration) -> ErrorOr { switch (declaration->kind()) { case DeclarationKind::DestructorDeclaration: case DeclarationKind::FunctionDeclaration: { auto& callable = cast(*declaration); if (callable.body().has_value()) { FunctionData data = {.declaration = &callable}; - CARBON_RETURN_IF_ERROR( - ResolveControlFlow(*callable.body(), std::nullopt, &data)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow( + trace_stream, *callable.body(), std::nullopt, &data)); } break; } case DeclarationKind::ClassDeclaration: { auto& class_decl = cast(*declaration); for (Nonnull member : class_decl.members()) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(member)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, member)); } break; } case DeclarationKind::MixinDeclaration: { auto& mixin_decl = cast(*declaration); for (Nonnull member : mixin_decl.members()) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(member)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, member)); } break; } @@ -162,21 +199,21 @@ auto ResolveControlFlow(Nonnull declaration) -> ErrorOr { case DeclarationKind::ConstraintDeclaration: { auto& iface_decl = cast(*declaration); for (Nonnull member : iface_decl.members()) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(member)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, member)); } break; } case DeclarationKind::ImplDeclaration: { auto& impl_decl = cast(*declaration); for (Nonnull member : impl_decl.members()) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(member)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, member)); } break; } case DeclarationKind::MatchFirstDeclaration: { auto& match_first_decl = cast(*declaration); for (Nonnull impl : match_first_decl.impl_declarations()) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(impl)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, impl)); } break; } @@ -196,9 +233,10 @@ auto ResolveControlFlow(Nonnull declaration) -> ErrorOr { return Success(); } -auto ResolveControlFlow(AST& ast) -> ErrorOr { +auto ResolveControlFlow(Nonnull trace_stream, AST& ast) + -> ErrorOr { for (auto* declaration : ast.declarations) { - CARBON_RETURN_IF_ERROR(ResolveControlFlow(declaration)); + CARBON_RETURN_IF_ERROR(ResolveControlFlow(trace_stream, declaration)); } return Success(); } diff --git a/explorer/interpreter/resolve_control_flow.h b/explorer/interpreter/resolve_control_flow.h index 0ec8bb123e3f..09ee8eccbd78 100644 --- a/explorer/interpreter/resolve_control_flow.h +++ b/explorer/interpreter/resolve_control_flow.h @@ -7,6 +7,7 @@ #include "explorer/ast/ast.h" #include "explorer/common/nonnull.h" +#include "explorer/common/trace_stream.h" namespace Carbon { @@ -14,7 +15,8 @@ namespace Carbon { // given AST. // On failure, `ast` is left in a partial state and should not be further // processed. -auto ResolveControlFlow(AST& ast) -> ErrorOr; +auto ResolveControlFlow(Nonnull trace_stream, AST& ast) + -> ErrorOr; } // namespace Carbon diff --git a/explorer/trace_testdata/full_trace.carbon b/explorer/trace_testdata/full_trace.carbon index 6ff7a412f8ec..1c3a0e6afaeb 100644 --- a/explorer/trace_testdata/full_trace.carbon +++ b/explorer/trace_testdata/full_trace.carbon @@ -76,6 +76,8 @@ fn Main() -> i32 { // CHECK:STDOUT: ** finished resolving decl `fn Main` (full_trace.carbon:18) // CHECK:STDOUT: --- resolved `Main` as `fn Main` in `package` (:0) // CHECK:STDOUT: ********** resolving control flow ********** +// CHECK:STDOUT: --- flow-resolved return statement `return (n + 1);` in `fn N.Foo` (full_trace.carbon:12) +// CHECK:STDOUT: --- flow-resolved return statement `return x;` in `fn Main` (full_trace.carbon:17) // CHECK:STDOUT: ********** type checking ********** // CHECK:STDOUT: ** declaring interface TestInterface // CHECK:STDOUT: ** finished declaring interface TestInterface