Просмотр исходного кода

Explorer: add more information to stack trace (#3040)

Adds **action kind** and **source location** for stack trace.
Example:
```
(+) stack-push: <action> (<source location>)
(+) stack-pop:  <action> (<source location>)
```
This PR also updates the `Action::Print(...)` method, following is the
generalized view of `Action::Print(...)`.
```
ActionKind pos: <pos_count> `<related_code>` results: [<collected_results>]  scope: [<scope>]
```
Prabhat Sachdeva 2 лет назад
Родитель
Сommit
2c4fff25a8

+ 58 - 20
explorer/README.md

@@ -175,33 +175,71 @@ The following options can be passed as a comma-separated list to the
 
 ### State of the Program
 
-The state of the program is printed in the following format, which consists of
-two components: (1) a stack of actions and (2) a memory.
+The state of the program is represented by the memory and the stack. The memory
+is a mapping of addresses to values, and the stack is a list of actions.
 
-    {
-    stack: action1 ## action2 ## ...
-    memory: 0: valueA, 1: valueB, 2: valueC, ...
-    }
+The state of the program is constantly changing as the program executes. The
+memory is updated as objects are allocated and deallocated, and the stack is
+updated as actions are performed. The state of the program can be used to track
+the progress of the program and to debug the program.
+
+#### Memory
 
 The memory is a mapping of addresses to values. The memory is used to represent
-both heap-allocated objects and also mutable parts of the procedure call stack,
-for example, for local variables. When an address is deallocated, it stays in
-memory but `!!` is printed before its value.
+both heap-allocated objects and also mutable parts of the procedure call stack.
+
+1. **Memory Allocation** is printed as
+
+```
+(+) memory-alloc: #<allocation_index> `value` uninitialized?
+```
+
+2. **Read Memory** is printed as
+
+```
++++ memory-read: #<allocation_index> `value`
+```
+
+3. **Write Memory** is printed as
+
+```
++++ memory-write: #<allocation_index> `value`
+```
+
+4. **Memory Deallocation** is printed as
+
+```
+(+) memory-dealloc: #<allocation_index> `value`
+```
+
+`allocation_index` is used for locating an object within the heap. `value`
+represents the object inside heap that is accessed using `allocation_index`
 
-The stack is list of actions separated by double pound signs (`##`). Each action
-has the format:
+#### Stack (Action Stack)
 
-    syntax .position. [[ results ]] { scope }
+The stack is list of actions, push and pop changes in the stack are printed in
+the following format
 
-which can have up to four parts.
+```
+(+) stack-push: <action> (<source location>)
+(+) stack-pop:  <action> (<source location>)
+```
+
+`action` is printed in the following format
+
+```
+ActionKind pos: <pos_count> `<syntax>` results: [<collected_results>]  scope: [<scope>]
+```
 
-1. The `syntax` for the part of the program to be executed such as an expression
-   or statement.
-2. The `position` of execution (an integer) for this action (each action can
-   take multiple steps to complete).
-3. The `results` from subexpressions of this part.
-4. The `scope` is the variables whose lifetimes are associated with this part of
-   the program.
+1. `ActionKind`: The kind of an action. Examples: ExpressionAction,
+   DeclarationAction, etc.
+2. `pos_count`: The position of execution (an integer) for this action. Each
+   action can take multiple steps to complete.
+3. `syntax`: The syntax for the part of the program to be executed, such as an
+   expression or statement.
+4. `collected_results`: The results from subexpressions of this part.
+5. `scope`: The variables whose lifetimes are associated with this part of the
+   program.
 
 The stack always begins with a function call to `Main`.
 

+ 43 - 27
explorer/interpreter/action.cpp

@@ -42,12 +42,12 @@ auto RuntimeScope::operator=(RuntimeScope&& rhs) noexcept -> RuntimeScope& {
 }
 
 void RuntimeScope::Print(llvm::raw_ostream& out) const {
-  out << "{";
+  out << "scope: [";
   llvm::ListSeparator sep;
   for (const auto& [value_node, value] : locals_) {
-    out << sep << value_node.base() << ": " << *value;
+    out << sep << "`" << value_node.base() << "`: `" << *value << "`";
   }
-  out << "}";
+  out << "]";
 }
 
 void RuntimeScope::Bind(ValueNodeView value_node, Address address) {
@@ -141,55 +141,71 @@ auto RuntimeScope::Capture(
 }
 
 void Action::Print(llvm::raw_ostream& out) const {
+  out << kind_string() << " pos: " << pos_ << " ";
   switch (kind()) {
     case Action::Kind::LocationAction:
-      out << cast<LocationAction>(*this).expression() << " ";
+      out << "`" << cast<LocationAction>(*this).expression() << "`";
       break;
     case Action::Kind::ValueExpressionAction:
-      out << cast<ValueExpressionAction>(*this).expression() << " ";
+      out << "`" << cast<ValueExpressionAction>(*this).expression() << "`";
       break;
     case Action::Kind::ExpressionAction:
-      out << cast<ExpressionAction>(*this).expression() << " ";
+      out << "`" << cast<ExpressionAction>(*this).expression() << "`";
       break;
     case Action::Kind::WitnessAction:
-      out << *cast<WitnessAction>(*this).witness() << " ";
+      out << "`" << *cast<WitnessAction>(*this).witness() << "`";
       break;
     case Action::Kind::StatementAction:
-      cast<StatementAction>(*this).statement().PrintDepth(1, out);
-      out << " ";
+      out << "`" << PrintAsID(cast<StatementAction>(*this).statement()) << "`";
       break;
     case Action::Kind::DeclarationAction:
-      cast<DeclarationAction>(*this).declaration().Print(out);
-      out << " ";
+      out << "`" << PrintAsID(cast<DeclarationAction>(*this).declaration())
+          << "`";
       break;
     case Action::Kind::TypeInstantiationAction:
-      cast<TypeInstantiationAction>(*this).type()->Print(out);
-      out << " ";
+      out << "`" << *cast<TypeInstantiationAction>(*this).type() << "`";
       break;
-    case Action::Kind::ScopeAction:
-      break;
-    case Action::Kind::RecursiveAction:
-      out << "recursive";
-      break;
-    case Action::Kind::CleanUpAction:
-      out << "clean up";
-      break;
-    case Action::Kind::DestroyAction:
-      out << "destroy";
+    default:
       break;
   }
-  out << "." << pos_ << ".";
   if (!results_.empty()) {
-    out << " [[";
+    out << " results: [";
     llvm::ListSeparator sep;
     for (const auto& result : results_) {
-      out << sep << *result;
+      out << sep << "`" << *result << "`";
     }
-    out << "]]";
+    out << "] ";
   }
   if (scope_.has_value()) {
     out << " " << *scope_;
   }
 }
 
+auto Action::kind_string() const -> std::string_view {
+  switch (kind()) {
+    case Action::Kind::LocationAction:
+      return "LocationAction";
+    case Action::Kind::ValueExpressionAction:
+      return "ValueExpressionAction";
+    case Action::Kind::ExpressionAction:
+      return "ExpressionAction";
+    case Action::Kind::WitnessAction:
+      return "WitnessAction";
+    case Action::Kind::StatementAction:
+      return "StatementAction";
+    case Action::Kind::DeclarationAction:
+      return "DeclarationAction";
+    case Action::Kind::TypeInstantiationAction:
+      return "TypeInstantiationAction";
+    case Action::Kind::ScopeAction:
+      return "ScopeAction";
+    case Action::Kind::RecursiveAction:
+      return "RecursiveAction";
+    case Action::Kind::CleanUpAction:
+      return "CleanUpAction";
+    case Action::Kind::DestroyAction:
+      return "DestroyAction";
+  }
+}
+
 }  // namespace Carbon

+ 2 - 0
explorer/interpreter/action.h

@@ -144,6 +144,8 @@ class Action {
   // object.
   auto kind() const -> Kind { return kind_; }
 
+  auto kind_string() const -> std::string_view;
+
   // The position or state of the action. Starts at 0 and is typically
   // incremented after each step.
   auto pos() const -> int { return pos_; }

+ 4 - 2
explorer/interpreter/action_stack.h

@@ -112,14 +112,16 @@ class ActionStack {
   auto Pop() -> std::unique_ptr<Action> {
     auto popped_action = todo_.Pop();
     if (trace_stream_->is_enabled()) {
-      *trace_stream_ << "(-) stack-pop: " << *popped_action << "\n";
+      *trace_stream_ << "(-) stack-pop:  " << *popped_action << " ("
+                     << popped_action->source_loc() << ")\n";
     }
     return popped_action;
   }
 
   void Push(std::unique_ptr<Action> action) {
     if (trace_stream_->is_enabled()) {
-      *trace_stream_ << "(+) stack-push: " << *action << "\n";
+      *trace_stream_ << "(+) stack-push: " << *action << " ("
+                     << action->source_loc() << ")\n";
     }
     todo_.Push(std::move(action));
   }

+ 13 - 30
explorer/interpreter/interpreter.cpp

@@ -503,10 +503,7 @@ auto PatternMatch(Nonnull<const Value*> p, ExpressionResult v,
 auto Interpreter::StepLocation() -> ErrorOr<Success> {
   Action& act = todo_.CurrentAction();
   const Expression& exp = cast<LocationAction>(act).expression();
-  if (trace_stream_->is_enabled()) {
-    *trace_stream_ << "--- step location " << exp << " ." << act.pos() << "."
-                   << " (" << exp.source_loc() << ") --->\n";
-  }
+
   switch (exp.kind()) {
     case ExpressionKind::IdentifierExpression: {
       //    { {x :: C, E, F} :: S, H}
@@ -1316,6 +1313,7 @@ auto Interpreter::StepInstantiateType() -> ErrorOr<Success> {
 
 auto Interpreter::StepValueExp() -> ErrorOr<Success> {
   auto& act = cast<ValueExpressionAction>(todo_.CurrentAction());
+
   if (act.pos() == 0) {
     return todo_.Spawn(std::make_unique<ExpressionAction>(
         &act.expression(), /*preserve_nested_categories=*/false,
@@ -1336,10 +1334,7 @@ auto Interpreter::StepValueExp() -> ErrorOr<Success> {
 auto Interpreter::StepExp() -> ErrorOr<Success> {
   auto& act = cast<ExpressionAction>(todo_.CurrentAction());
   const Expression& exp = act.expression();
-  if (trace_stream_->is_enabled()) {
-    *trace_stream_ << "--- step exp " << exp << " ." << act.pos() << "."
-                   << " (" << exp.source_loc() << ") --->\n";
-  }
+
   switch (exp.kind()) {
     case ExpressionKind::IndexExpression: {
       if (act.pos() == 0) {
@@ -2103,10 +2098,7 @@ auto Interpreter::StepExp() -> ErrorOr<Success> {
 auto Interpreter::StepWitness() -> ErrorOr<Success> {
   auto& act = cast<WitnessAction>(todo_.CurrentAction());
   const Witness* witness = act.witness();
-  if (trace_stream_->is_enabled()) {
-    *trace_stream_ << "--- step witness " << *witness << " ." << act.pos()
-                   << ". --->\n";
-  }
+
   switch (witness->kind()) {
     case Value::Kind::BindingWitness: {
       const ImplBinding* binding = cast<BindingWitness>(witness)->binding();
@@ -2169,12 +2161,7 @@ auto Interpreter::StepWitness() -> ErrorOr<Success> {
 auto Interpreter::StepStmt() -> ErrorOr<Success> {
   auto& act = cast<StatementAction>(todo_.CurrentAction());
   const Statement& stmt = act.statement();
-  if (trace_stream_->is_enabled()) {
-    *trace_stream_ << "--- step stmt ";
-    stmt.PrintDepth(1, trace_stream_->stream());
-    *trace_stream_ << " ." << act.pos() << ". "
-                   << "(" << stmt.source_loc() << ") --->\n";
-  }
+
   switch (stmt.kind()) {
     case StatementKind::Match: {
       const auto& match_stmt = cast<Match>(stmt);
@@ -2497,12 +2484,6 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
     case StatementKind::ReturnVar: {
       const auto& ret_var = cast<ReturnVar>(stmt);
       const ValueNodeView& value_node = ret_var.value_node();
-      if (trace_stream_->is_enabled()) {
-        *trace_stream_ << "--- step returned var "
-                       << cast<BindingPattern>(value_node.base()).name() << " ."
-                       << act.pos() << "."
-                       << " (" << stmt.source_loc() << ") --->\n";
-      }
       CARBON_ASSIGN_OR_RETURN(Nonnull<const Value*> value,
                               todo_.ValueOfNode(value_node, stmt.source_loc()));
       if (const auto* location = dyn_cast<LocationValue>(value)) {
@@ -2543,12 +2524,7 @@ auto Interpreter::StepStmt() -> ErrorOr<Success> {
 auto Interpreter::StepDeclaration() -> ErrorOr<Success> {
   Action& act = todo_.CurrentAction();
   const Declaration& decl = cast<DeclarationAction>(act).declaration();
-  if (trace_stream_->is_enabled()) {
-    *trace_stream_ << "--- step decl ";
-    decl.PrintID(trace_stream_->stream());
-    *trace_stream_ << " ." << act.pos() << ". "
-                   << "(" << decl.source_loc() << ") --->\n";
-  }
+
   switch (decl.kind()) {
     case DeclarationKind::VariableDeclaration: {
       const auto& var_decl = cast<VariableDeclaration>(decl);
@@ -2596,6 +2572,7 @@ auto Interpreter::StepDeclaration() -> ErrorOr<Success> {
 auto Interpreter::StepDestroy() -> ErrorOr<Success> {
   const Action& act = todo_.CurrentAction();
   const auto& destroy_act = cast<DestroyAction>(act);
+
   switch (destroy_act.value()->kind()) {
     case Value::Kind::NominalClassValue: {
       const auto* class_obj = cast<NominalClassValue>(destroy_act.value());
@@ -2676,6 +2653,7 @@ auto Interpreter::StepDestroy() -> ErrorOr<Success> {
 auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
   const Action& act = todo_.CurrentAction();
   const auto& cleanup = cast<CleanUpAction>(act);
+
   if (act.pos() < cleanup.allocations_count() * 2) {
     const size_t alloc_index = cleanup.allocations_count() - act.pos() / 2 - 1;
     auto allocation = act.scope()->allocations()[alloc_index];
@@ -2705,6 +2683,11 @@ auto Interpreter::StepCleanUp() -> ErrorOr<Success> {
 auto Interpreter::Step() -> ErrorOr<Success> {
   Action& act = todo_.CurrentAction();
 
+  if (trace_stream_->is_enabled()) {
+    *trace_stream_ << "--- step " << act << " (" << act.source_loc()
+                   << ") --->\n";
+  }
+
   auto error_builder = [&] {
     if (auto loc = act.source_loc()) {
       return ProgramError(*loc);

+ 1 - 1
explorer/testdata/trace/context_all.carbon

@@ -19,4 +19,4 @@ fn Main() -> i32 {
 // CHECK:STDOUT: ** declaring function Main
 // CHECK:STDOUT: interface As {
 // CHECK:STDOUT: fn Main ()-> i32 {
-// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main()` (<Main()>:0) --->

+ 54 - 59
explorer/testdata/trace/context_main.carbon

@@ -53,11 +53,13 @@ fn Main() -> i32 {
 // CHECK:STDOUT: ** declaring function Main
 // CHECK:STDOUT: checking TuplePattern ()
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (context_main.carbon:9) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (context_main.carbon:9)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (context_main.carbon:9) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (context_main.carbon:9)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (context_main.carbon:9) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (context_main.carbon:9)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (context_main.carbon:9) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (context_main.carbon:9)
 // CHECK:STDOUT: ** finished declaring function Main of type fn () -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Main
@@ -93,64 +95,57 @@ fn Main() -> i32 {
 // CHECK:STDOUT: }
 // CHECK:STDOUT: ********** starting execution **********
 // CHECK:STDOUT: ********** initializing globals **********
-// CHECK:STDOUT: (+) stack-push: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl interface TestInterface .0. (context_main.carbon:7) --->
-// CHECK:STDOUT: (-) stack-pop: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: (+) stack-push: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return 0;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn Main .0. (context_main.carbon:11) --->
-// CHECK:STDOUT: (-) stack-pop: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return 0;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `interface TestInterface` (context_main.carbon:7)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `interface TestInterface` (context_main.carbon:7) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `interface TestInterface` (context_main.carbon:7)
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `fn Main` (context_main.carbon:11)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `fn Main` (context_main.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `fn Main` (context_main.carbon:11)
 // CHECK:STDOUT: ********** calling main function **********
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: --- step exp Main .0. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main .0.
-// CHECK:STDOUT: (-) stack-pop: Main .1. {{\[\[}}fun<Main>]]
-// CHECK:STDOUT: --- step exp Main() .1. (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 1 `Main()` results: [`fun<Main>`]  scope: [] (<Main()>:0) --->
 // CHECK:STDOUT: calling function: fun<Main>
 // CHECK:STDOUT: match pattern ()
 // CHECK:STDOUT: from value expression with value ()
-// CHECK:STDOUT: (+) stack-push: .0. {}
-// CHECK:STDOUT: (+) stack-push: {return 0;} .0.
-// CHECK:STDOUT: --- step stmt {return 0;} .0. (context_main.carbon:11) --->
-// CHECK:STDOUT: (+) stack-push: return 0; .0.
-// CHECK:STDOUT: --- step stmt return 0; .0. (context_main.carbon:10) --->
-// CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: --- step exp 0 .0. (context_main.carbon:10) --->
-// CHECK:STDOUT: (-) stack-pop: 0 .0.
-// CHECK:STDOUT: (-) stack-pop: 0 .1. {{\[\[}}0]]
-// CHECK:STDOUT: --- step stmt return 0; .1. (context_main.carbon:10) --->
-// CHECK:STDOUT: (-) stack-pop: return 0; .1. {{\[\[}}0]]
-// CHECK:STDOUT: (-) stack-pop: {return 0;} .1. {}
-// CHECK:STDOUT: (-) stack-pop: .0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: --- step exp Main() .2. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main() .2. {{\[\[}}fun<Main>, 0]] {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: Main() .1. {{\[\[}}0]]
+// CHECK:STDOUT: (+) stack-push: ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `{return 0;}` (context_main.carbon:11)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `{return 0;}` (context_main.carbon:11) --->
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `return 0;` (context_main.carbon:10)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `return 0;` (context_main.carbon:10) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `0` (context_main.carbon:10)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `0` (context_main.carbon:10) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `0` (context_main.carbon:10)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `0` (context_main.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `0` (context_main.carbon:10)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `0` results: [`0`]  (context_main.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `0` results: [`0`]  (context_main.carbon:10)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `return 0;` results: [`0`]  (context_main.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `return 0;` results: [`0`]  (context_main.carbon:10)
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `{return 0;}` scope: [] (context_main.carbon:11)
+// CHECK:STDOUT: (-) stack-pop:  ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `0`]  scope: [] (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `0`]  scope: [] (<Main()>:0)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main()` results: [`0`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main()` results: [`0`]  (<Main()>:0)
 // CHECK:STDOUT: interpreter result: 0
 // CHECK:STDOUT: ********** printing timing **********
 // CHECK:STDOUT: Time elapsed in ExecProgram: {{\d+}}ms

+ 151 - 150
explorer/testdata/trace/phase_all.carbon

@@ -94,18 +94,22 @@ fn Main() -> i32 {
 // CHECK:STDOUT: checking BindingPattern n: i32
 // CHECK:STDOUT: checking ExpressionPattern i32
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:11) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (phase_all.carbon:11) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (phase_all.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:11)
 // CHECK:STDOUT: finished checking tuple pattern field n: i32
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:11) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (phase_all.carbon:11) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (phase_all.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (phase_all.carbon:11)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:11)
 // CHECK:STDOUT: ** finished declaring function Foo of type fn (i32,) -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Foo
@@ -123,11 +127,13 @@ fn Main() -> i32 {
 // CHECK:STDOUT: ** declaring function Main
 // CHECK:STDOUT: checking TuplePattern ()
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:15) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (phase_all.carbon:15)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (phase_all.carbon:15) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (phase_all.carbon:15)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (phase_all.carbon:15) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (phase_all.carbon:15)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:15) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:15)
 // CHECK:STDOUT: ** finished declaring function Main of type fn () -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Main
@@ -152,11 +158,13 @@ fn Main() -> i32 {
 // CHECK:STDOUT: checking BindingPattern x: i32, expecting i32
 // CHECK:STDOUT: checking ExpressionPattern i32, expecting i32
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_all.carbon:16)
 // CHECK:STDOUT: checking ReturnExpression return x;
 // CHECK:STDOUT: checking IdentifierExpression x
 // CHECK:STDOUT: ** finished checking function Main
@@ -198,153 +206,146 @@ fn Main() -> i32 {
 // CHECK:STDOUT: }
 // CHECK:STDOUT: ********** starting execution **********
 // CHECK:STDOUT: ********** initializing globals **********
-// CHECK:STDOUT: (+) stack-push: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl interface TestInterface .0. (phase_all.carbon:7) --->
-// CHECK:STDOUT: (-) stack-pop: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: (+) stack-push: namespace N; .0.
-// CHECK:STDOUT: --- step decl namespace N .0. (phase_all.carbon:9) --->
-// CHECK:STDOUT: (-) stack-pop: namespace N; .0.
-// CHECK:STDOUT: (+) stack-push: fn Foo (n: i32)-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return (n + 1);
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn N.Foo .0. (phase_all.carbon:13) --->
-// CHECK:STDOUT: (-) stack-pop: fn Foo (n: i32)-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return (n + 1);
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: (+) stack-push: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: var x: i32 = N.Foo(0);
-// CHECK:STDOUT: return x;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn Main .0. (phase_all.carbon:18) --->
-// CHECK:STDOUT: (-) stack-pop: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: var x: i32 = N.Foo(0);
-// CHECK:STDOUT: return x;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `interface TestInterface` (phase_all.carbon:7)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `interface TestInterface` (phase_all.carbon:7) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `interface TestInterface` (phase_all.carbon:7)
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `namespace N` (phase_all.carbon:9)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `namespace N` (phase_all.carbon:9) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `namespace N` (phase_all.carbon:9)
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `fn N.Foo` (phase_all.carbon:13)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `fn N.Foo` (phase_all.carbon:13) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `fn N.Foo` (phase_all.carbon:13)
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `fn Main` (phase_all.carbon:18)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `fn Main` (phase_all.carbon:18) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `fn Main` (phase_all.carbon:18)
 // CHECK:STDOUT: ********** calling main function **********
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: --- step exp Main .0. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main .0.
-// CHECK:STDOUT: (-) stack-pop: Main .1. {{\[\[}}fun<Main>]]
-// CHECK:STDOUT: --- step exp Main() .1. (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 1 `Main()` results: [`fun<Main>`]  scope: [] (<Main()>:0) --->
 // CHECK:STDOUT: calling function: fun<Main>
 // CHECK:STDOUT: match pattern ()
 // CHECK:STDOUT: from value expression with value ()
-// CHECK:STDOUT: (+) stack-push: .0. {}
-// CHECK:STDOUT: (+) stack-push: {var x: i32 = N.Foo(0);return x;} .0.
-// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .0. (phase_all.carbon:18) --->
-// CHECK:STDOUT: (+) stack-push: var x: i32 = N.Foo(0); .0.
-// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .0. (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:18)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `{var x: i32 = N.Foo(0);return x;}` (phase_all.carbon:18) --->
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `var x: i32 = N.Foo(0);` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `var x: i32 = N.Foo(0);` (phase_all.carbon:16) --->
 // CHECK:STDOUT: (+) memory-alloc: #1 `Uninit<i32>` uninitialized
-// CHECK:STDOUT: (+) stack-push: N.Foo(0) .0.
-// CHECK:STDOUT: --- step exp N.Foo(0) .0. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (+) stack-push: N.Foo .0.
-// CHECK:STDOUT: (+) stack-push: N.Foo .0.
-// CHECK:STDOUT: --- step exp N.Foo .0. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: N.Foo .0.
-// CHECK:STDOUT: (+) stack-push: Foo .0.
-// CHECK:STDOUT: --- step exp Foo .0. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: Foo .0.
-// CHECK:STDOUT: (-) stack-pop: N.Foo .1. {{\[\[}}fun<N.Foo>]]
-// CHECK:STDOUT: --- step exp N.Foo(0) .1. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: --- step exp 0 .0. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: 0 .0.
-// CHECK:STDOUT: --- step exp N.Foo(0) .2. (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `N.Foo(0)` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `N.Foo(0)` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `N.Foo` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `N.Foo` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `N.Foo` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `N.Foo` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `N.Foo` (phase_all.carbon:16)
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Foo` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Foo` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `Foo` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `N.Foo` results: [`fun<N.Foo>`]  (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `N.Foo` results: [`fun<N.Foo>`]  (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 1 `N.Foo(0)` results: [`fun<N.Foo>`]  scope: [] (phase_all.carbon:16) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `0` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `0` (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `0` (phase_all.carbon:16)
+// CHECK:STDOUT: --- step ExpressionAction pos: 2 `N.Foo(0)` results: [`fun<N.Foo>`, `0`]  scope: [] (phase_all.carbon:16) --->
 // CHECK:STDOUT: calling function: fun<N.Foo>
 // CHECK:STDOUT: match pattern (Placeholder<n>,)
 // CHECK:STDOUT: from value expression with value (0,)
 // CHECK:STDOUT: match pattern Placeholder<n>
 // CHECK:STDOUT: from value expression with value 0
-// CHECK:STDOUT: (+) stack-push: .0. {n: i32: 0}
-// CHECK:STDOUT: (+) stack-push: {return (n + 1);} .0.
-// CHECK:STDOUT: --- step stmt {return (n + 1);} .0. (phase_all.carbon:13) --->
-// CHECK:STDOUT: (+) stack-push: return (n + 1); .0.
-// CHECK:STDOUT: --- step stmt return (n + 1); .0. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (+) stack-push: (n + 1) .0.
-// CHECK:STDOUT: (+) stack-push: (n + 1) .0.
-// CHECK:STDOUT: --- step exp (n + 1) .0. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (+) stack-push: n .0.
-// CHECK:STDOUT: (+) stack-push: n .0.
-// CHECK:STDOUT: --- step exp n .0. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (-) stack-pop: n .0.
-// CHECK:STDOUT: (-) stack-pop: n .1. {{\[\[}}0]]
-// CHECK:STDOUT: --- step exp (n + 1) .1. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (+) stack-push: 1 .0.
-// CHECK:STDOUT: (+) stack-push: 1 .0.
-// CHECK:STDOUT: --- step exp 1 .0. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (-) stack-pop: 1 .0.
-// CHECK:STDOUT: (-) stack-pop: 1 .1. {{\[\[}}1]]
-// CHECK:STDOUT: --- step exp (n + 1) .2. (phase_all.carbon:12) --->
-// CHECK:STDOUT: (-) stack-pop: (n + 1) .2. {{\[\[}}0, 1]]
-// CHECK:STDOUT: (-) stack-pop: (n + 1) .1. {{\[\[}}1]]
-// CHECK:STDOUT: --- step stmt return (n + 1); .1. (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ScopeAction pos: 0  scope: [`n: i32`: `0`] (None)
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `{return (n + 1);}` (phase_all.carbon:13)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `{return (n + 1);}` (phase_all.carbon:13) --->
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `return (n + 1);` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `return (n + 1);` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `(n + 1)` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `(n + 1)` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `(n + 1)` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `(n + 1)` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `n` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `n` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `n` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `n` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `n` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `n` results: [`0`]  (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `n` results: [`0`]  (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ExpressionAction pos: 1 `(n + 1)` results: [`0`]  (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `1` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `1` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `1` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `1` (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `1` (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `1` results: [`1`]  (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `1` results: [`1`]  (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ExpressionAction pos: 2 `(n + 1)` results: [`0`, `1`]  (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 2 `(n + 1)` results: [`0`, `1`]  (phase_all.carbon:12)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `(n + 1)` results: [`1`]  (phase_all.carbon:12) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `(n + 1)` results: [`1`]  (phase_all.carbon:12)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `return (n + 1);` results: [`1`]  (phase_all.carbon:12) --->
 // CHECK:STDOUT: +++ memory-write: #1 `1`
-// CHECK:STDOUT: (-) stack-pop: return (n + 1); .1. {{\[\[}}1]]
-// CHECK:STDOUT: (-) stack-pop: {return (n + 1);} .1. {}
-// CHECK:STDOUT: (-) stack-pop: .0. {n: i32: 0}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {n: i32: 0}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {n: i32: 0}
-// CHECK:STDOUT: --- step exp N.Foo(0) .3. (phase_all.carbon:16) --->
-// CHECK:STDOUT: (-) stack-pop: N.Foo(0) .3. {{\[\[}}fun<N.Foo>, 0, 1]] {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: --- step stmt var x: i32 = N.Foo(0); .1. (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `return (n + 1);` results: [`1`]  (phase_all.carbon:12)
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `{return (n + 1);}` scope: [] (phase_all.carbon:13)
+// CHECK:STDOUT: (-) stack-pop:  ScopeAction pos: 0  scope: [`n: i32`: `0`] (None)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [`n: i32`: `0`] (stack cleanup:1)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [`n: i32`: `0`] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [`n: i32`: `0`] (stack cleanup:1)
+// CHECK:STDOUT: --- step ExpressionAction pos: 3 `N.Foo(0)` results: [`fun<N.Foo>`, `0`, `1`]  scope: [] (phase_all.carbon:16) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 3 `N.Foo(0)` results: [`fun<N.Foo>`, `0`, `1`]  scope: [] (phase_all.carbon:16)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `var x: i32 = N.Foo(0);` results: [`1`]  (phase_all.carbon:16) --->
 // CHECK:STDOUT: +++ memory-read: #1 `1`
 // CHECK:STDOUT: match pattern Placeholder<x>
 // CHECK:STDOUT: from initializing expression with value 1
-// CHECK:STDOUT: (-) stack-pop: var x: i32 = N.Foo(0); .1. {{\[\[}}1]]
-// CHECK:STDOUT: --- step stmt {var x: i32 = N.Foo(0);return x;} .1. (phase_all.carbon:18) --->
-// CHECK:STDOUT: (+) stack-push: return x; .0.
-// CHECK:STDOUT: --- step stmt return x; .0. (phase_all.carbon:17) --->
-// CHECK:STDOUT: (+) stack-push: x .0.
-// CHECK:STDOUT: (+) stack-push: x .0.
-// CHECK:STDOUT: --- step exp x .0. (phase_all.carbon:17) --->
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `var x: i32 = N.Foo(0);` results: [`1`]  (phase_all.carbon:16)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `{var x: i32 = N.Foo(0);return x;}` scope: [`x: i32`: `lval<Allocation(1)>`] (phase_all.carbon:18) --->
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `return x;` (phase_all.carbon:17)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `return x;` (phase_all.carbon:17) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `x` (phase_all.carbon:17)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `x` (phase_all.carbon:17) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `x` (phase_all.carbon:17)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `x` (phase_all.carbon:17) --->
 // CHECK:STDOUT: +++ memory-read: #1 `1`
-// CHECK:STDOUT: (-) stack-pop: x .0.
-// CHECK:STDOUT: (-) stack-pop: x .1. {{\[\[}}ref_expr<Allocation(1)>]]
-// CHECK:STDOUT: --- step stmt return x; .1. (phase_all.carbon:17) --->
-// CHECK:STDOUT: (-) stack-pop: return x; .1. {{\[\[}}1]]
-// CHECK:STDOUT: (-) stack-pop: {var x: i32 = N.Foo(0);return x;} .2. {x: i32: lval<Allocation(1)>}
-// CHECK:STDOUT: (-) stack-pop: .0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {x: i32: lval<Allocation(1)>}
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `x` (phase_all.carbon:17)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `x` results: [`ref_expr<Allocation(1)>`]  (phase_all.carbon:17) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `x` results: [`ref_expr<Allocation(1)>`]  (phase_all.carbon:17)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `return x;` results: [`1`]  (phase_all.carbon:17) --->
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `return x;` results: [`1`]  (phase_all.carbon:17)
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 2 `{var x: i32 = N.Foo(0);return x;}` scope: [`x: i32`: `lval<Allocation(1)>`] (phase_all.carbon:18)
+// CHECK:STDOUT: (-) stack-pop:  ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [`x: i32`: `lval<Allocation(1)>`] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [`x: i32`: `lval<Allocation(1)>`] (stack cleanup:1) --->
 // CHECK:STDOUT: +++ memory-read: #1 `1`
-// CHECK:STDOUT: (+) stack-push: destroy.0.
-// CHECK:STDOUT: (-) stack-pop: destroy.0.
+// CHECK:STDOUT: (+) stack-push: DestroyAction pos: 0  (None)
+// CHECK:STDOUT: --- step DestroyAction pos: 0  (None) --->
+// CHECK:STDOUT: (-) stack-pop:  DestroyAction pos: 0  (None)
+// CHECK:STDOUT: --- step CleanUpAction pos: 1  scope: [`x: i32`: `lval<Allocation(1)>`] (stack cleanup:1) --->
 // CHECK:STDOUT: (-) memory-dealloc: #1 `1`
-// CHECK:STDOUT: (-) stack-pop: clean up.2. {x: i32: lval<Allocation(1)>}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: --- step exp Main() .2. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main() .2. {{\[\[}}fun<Main>, 1]] {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: Main() .1. {{\[\[}}1]]
+// CHECK:STDOUT: --- step CleanUpAction pos: 2  scope: [`x: i32`: `lval<Allocation(1)>`] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 2  scope: [`x: i32`: `lval<Allocation(1)>`] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `1`]  scope: [] (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `1`]  scope: [] (<Main()>:0)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main()` results: [`1`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main()` results: [`1`]  (<Main()>:0)
 // CHECK:STDOUT: interpreter result: 1
 // CHECK:STDOUT: ********** printing timing **********
 // CHECK:STDOUT: Time elapsed in ExecProgram: {{\d+}}ms

+ 47 - 54
explorer/testdata/trace/phase_execution.carbon

@@ -16,63 +16,56 @@ fn Main() -> i32 {
 // AUTOUPDATE
 // CHECK:STDOUT: ********** starting execution **********
 // CHECK:STDOUT: ********** initializing globals **********
-// CHECK:STDOUT: (+) stack-push: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl interface TestInterface .0. (phase_execution.carbon:7) --->
-// CHECK:STDOUT: (-) stack-pop: interface TestInterface {
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: (+) stack-push: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return 0;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
-// CHECK:STDOUT: --- step decl fn Main .0. (phase_execution.carbon:11) --->
-// CHECK:STDOUT: (-) stack-pop: fn Main ()-> i32 {
-// CHECK:STDOUT: {
-// CHECK:STDOUT: return 0;
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: }
-// CHECK:STDOUT:  .0.
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `interface TestInterface` (phase_execution.carbon:7)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `interface TestInterface` (phase_execution.carbon:7) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `interface TestInterface` (phase_execution.carbon:7)
+// CHECK:STDOUT: (+) stack-push: DeclarationAction pos: 0 `fn Main` (phase_execution.carbon:11)
+// CHECK:STDOUT: --- step DeclarationAction pos: 0 `fn Main` (phase_execution.carbon:11) --->
+// CHECK:STDOUT: (-) stack-pop:  DeclarationAction pos: 0 `fn Main` (phase_execution.carbon:11)
 // CHECK:STDOUT: ********** calling main function **********
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: (+) stack-push: Main() .0.
-// CHECK:STDOUT: --- step exp Main() .0. (<Main()>:0) --->
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: (+) stack-push: Main .0.
-// CHECK:STDOUT: --- step exp Main .0. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main .0.
-// CHECK:STDOUT: (-) stack-pop: Main .1. {{\[\[}}fun<Main>]]
-// CHECK:STDOUT: --- step exp Main() .1. (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main()` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main()` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `Main` (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `Main` (<Main()>:0)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main` results: [`fun<Main>`]  (<Main()>:0)
+// CHECK:STDOUT: --- step ExpressionAction pos: 1 `Main()` results: [`fun<Main>`]  scope: [] (<Main()>:0) --->
 // CHECK:STDOUT: calling function: fun<Main>
 // CHECK:STDOUT: match pattern ()
 // CHECK:STDOUT: from value expression with value ()
-// CHECK:STDOUT: (+) stack-push: .0. {}
-// CHECK:STDOUT: (+) stack-push: {return 0;} .0.
-// CHECK:STDOUT: --- step stmt {return 0;} .0. (phase_execution.carbon:11) --->
-// CHECK:STDOUT: (+) stack-push: return 0; .0.
-// CHECK:STDOUT: --- step stmt return 0; .0. (phase_execution.carbon:10) --->
-// CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: (+) stack-push: 0 .0.
-// CHECK:STDOUT: --- step exp 0 .0. (phase_execution.carbon:10) --->
-// CHECK:STDOUT: (-) stack-pop: 0 .0.
-// CHECK:STDOUT: (-) stack-pop: 0 .1. {{\[\[}}0]]
-// CHECK:STDOUT: --- step stmt return 0; .1. (phase_execution.carbon:10) --->
-// CHECK:STDOUT: (-) stack-pop: return 0; .1. {{\[\[}}0]]
-// CHECK:STDOUT: (-) stack-pop: {return 0;} .1. {}
-// CHECK:STDOUT: (-) stack-pop: .0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: --- step exp Main() .2. (<Main()>:0) --->
-// CHECK:STDOUT: (-) stack-pop: Main() .2. {{\[\[}}fun<Main>, 0]] {}
-// CHECK:STDOUT: (+) stack-push: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: clean up.0. {}
-// CHECK:STDOUT: (-) stack-pop: Main() .1. {{\[\[}}0]]
+// CHECK:STDOUT: (+) stack-push: ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `{return 0;}` (phase_execution.carbon:11)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `{return 0;}` (phase_execution.carbon:11) --->
+// CHECK:STDOUT: (+) stack-push: StatementAction pos: 0 `return 0;` (phase_execution.carbon:10)
+// CHECK:STDOUT: --- step StatementAction pos: 0 `return 0;` (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `0` (phase_execution.carbon:10)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `0` (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `0` (phase_execution.carbon:10)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `0` (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `0` (phase_execution.carbon:10)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `0` results: [`0`]  (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `0` results: [`0`]  (phase_execution.carbon:10)
+// CHECK:STDOUT: --- step StatementAction pos: 1 `return 0;` results: [`0`]  (phase_execution.carbon:10) --->
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `return 0;` results: [`0`]  (phase_execution.carbon:10)
+// CHECK:STDOUT: (-) stack-pop:  StatementAction pos: 1 `{return 0;}` scope: [] (phase_execution.carbon:11)
+// CHECK:STDOUT: (-) stack-pop:  ScopeAction pos: 0  scope: [] (None)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `0`]  scope: [] (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 2 `Main()` results: [`fun<Main>`, `0`]  scope: [] (<Main()>:0)
+// CHECK:STDOUT: (+) stack-push: CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step CleanUpAction pos: 0  scope: [] (stack cleanup:1) --->
+// CHECK:STDOUT: (-) stack-pop:  CleanUpAction pos: 0  scope: [] (stack cleanup:1)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `Main()` results: [`0`]  (<Main()>:0) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `Main()` results: [`0`]  (<Main()>:0)
 // CHECK:STDOUT: interpreter result: 0
 // CHECK:STDOUT: result: 0

+ 7 - 5
explorer/testdata/trace/phase_type_checking.carbon

@@ -25,11 +25,13 @@ fn Main() -> i32 {
 // CHECK:STDOUT: ** declaring function Main
 // CHECK:STDOUT: checking TuplePattern ()
 // CHECK:STDOUT: checking IntTypeLiteral i32
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: (+) stack-push: i32 .0.
-// CHECK:STDOUT: --- step exp i32 .0. (phase_type_checking.carbon:9) --->
-// CHECK:STDOUT: (-) stack-pop: i32 .0.
-// CHECK:STDOUT: (-) stack-pop: i32 .1. {{\[\[}}i32]]
+// CHECK:STDOUT: (+) stack-push: ValueExpressionAction pos: 0 `i32` (phase_type_checking.carbon:9)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 0 `i32` (phase_type_checking.carbon:9) --->
+// CHECK:STDOUT: (+) stack-push: ExpressionAction pos: 0 `i32` (phase_type_checking.carbon:9)
+// CHECK:STDOUT: --- step ExpressionAction pos: 0 `i32` (phase_type_checking.carbon:9) --->
+// CHECK:STDOUT: (-) stack-pop:  ExpressionAction pos: 0 `i32` (phase_type_checking.carbon:9)
+// CHECK:STDOUT: --- step ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_type_checking.carbon:9) --->
+// CHECK:STDOUT: (-) stack-pop:  ValueExpressionAction pos: 1 `i32` results: [`i32`]  (phase_type_checking.carbon:9)
 // CHECK:STDOUT: ** finished declaring function Main of type fn () -> i32
 // CHECK:STDOUT: checking FunctionDeclaration
 // CHECK:STDOUT: ** checking function Main