فهرست منبع

Remove global_arena (#814)

With this, only main.cpp instantiates an arena. Maybe we'll want to split that up more later (e.g., so that the runtime interpreter uses its own arena), but given the intent to have type-checking update the AST, I thought this was a reasonable approach for now in order to avoid ownership complexities.

Fixes #769
Jon Meow 4 سال پیش
والد
کامیت
90f04700e2

+ 6 - 6
executable_semantics/ast/expression.cpp

@@ -17,21 +17,21 @@ namespace Carbon {
 using llvm::cast;
 
 auto ExpressionFromParenContents(
-    SourceLocation loc, const ParenContents<Expression>& paren_contents)
-    -> Ptr<const Expression> {
+    Ptr<Arena> arena, SourceLocation loc,
+    const ParenContents<Expression>& paren_contents) -> Ptr<const Expression> {
   std::optional<Ptr<const Expression>> single_term =
       paren_contents.SingleTerm();
   if (single_term.has_value()) {
     return *single_term;
   } else {
-    return TupleExpressionFromParenContents(loc, paren_contents);
+    return TupleExpressionFromParenContents(arena, loc, paren_contents);
   }
 }
 
 auto TupleExpressionFromParenContents(
-    SourceLocation loc, const ParenContents<Expression>& paren_contents)
-    -> Ptr<const Expression> {
-  return global_arena->New<TupleLiteral>(
+    Ptr<Arena> arena, SourceLocation loc,
+    const ParenContents<Expression>& paren_contents) -> Ptr<const Expression> {
+  return arena->New<TupleLiteral>(
       loc, paren_contents.TupleElements<FieldInitializer>(loc));
 }
 

+ 5 - 4
executable_semantics/ast/expression.h

@@ -13,6 +13,7 @@
 #include "common/ostream.h"
 #include "executable_semantics/ast/paren_contents.h"
 #include "executable_semantics/ast/source_location.h"
+#include "executable_semantics/common/arena.h"
 #include "llvm/Support/Compiler.h"
 
 namespace Carbon {
@@ -62,14 +63,14 @@ class Expression {
 // grouping if their contents permit that interpretation, or as forming a
 // tuple otherwise.
 auto ExpressionFromParenContents(
-    SourceLocation loc, const ParenContents<Expression>& paren_contents)
-    -> Ptr<const Expression>;
+    Ptr<Arena> arena, SourceLocation loc,
+    const ParenContents<Expression>& paren_contents) -> Ptr<const Expression>;
 
 // Converts paren_contents to an Expression, interpreting the parentheses as
 // forming a tuple.
 auto TupleExpressionFromParenContents(
-    SourceLocation loc, const ParenContents<Expression>& paren_contents)
-    -> Ptr<const Expression>;
+    Ptr<Arena> arena, SourceLocation loc,
+    const ParenContents<Expression>& paren_contents) -> Ptr<const Expression>;
 
 // A FieldInitializer represents the initialization of a single tuple field.
 struct FieldInitializer {

+ 33 - 36
executable_semantics/ast/expression_test.cpp

@@ -30,27 +30,32 @@ static auto FakeSourceLoc(int line_num) -> SourceLocation {
   return SourceLocation("<test>", line_num);
 }
 
-TEST(ExpressionTest, EmptyAsExpression) {
+class ExpressionTest : public ::testing::Test {
+ protected:
+  Arena arena;
+};
+
+TEST_F(ExpressionTest, EmptyAsExpression) {
   ParenContents<Expression> contents = {.elements = {},
                                         .has_trailing_comma = false};
   Ptr<const Expression> expression =
-      ExpressionFromParenContents(FakeSourceLoc(1), contents);
+      ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(), IsEmpty());
 }
 
-TEST(ExpressionTest, EmptyAsTuple) {
+TEST_F(ExpressionTest, EmptyAsTuple) {
   ParenContents<Expression> contents = {.elements = {},
                                         .has_trailing_comma = false};
-  Ptr<const Expression> tuple =
-      TupleExpressionFromParenContents(FakeSourceLoc(1), contents);
+  Ptr<const Expression> tuple = TupleExpressionFromParenContents(
+      PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(), IsEmpty());
 }
 
-TEST(ExpressionTest, UnaryNoCommaAsExpression) {
+TEST_F(ExpressionTest, UnaryNoCommaAsExpression) {
   // Equivalent to a code fragment like
   // ```
   // (
@@ -59,91 +64,83 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) {
   // ```
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)}},
       .has_trailing_comma = false};
 
   Ptr<const Expression> expression =
-      ExpressionFromParenContents(FakeSourceLoc(1), contents);
+      ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(2));
   ASSERT_EQ(expression->Tag(), Expression::Kind::IntLiteral);
 }
 
-TEST(ExpressionTest, UnaryNoCommaAsTuple) {
+TEST_F(ExpressionTest, UnaryNoCommaAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)}},
       .has_trailing_comma = false};
 
-  Ptr<const Expression> tuple =
-      TupleExpressionFromParenContents(FakeSourceLoc(1), contents);
+  Ptr<const Expression> tuple = TupleExpressionFromParenContents(
+      PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
               ElementsAre(IntFieldNamed("0")));
 }
 
-TEST(ExpressionTest, UnaryWithCommaAsExpression) {
+TEST_F(ExpressionTest, UnaryWithCommaAsExpression) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)}},
       .has_trailing_comma = true};
 
   Ptr<const Expression> expression =
-      ExpressionFromParenContents(FakeSourceLoc(1), contents);
+      ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
               ElementsAre(IntFieldNamed("0")));
 }
 
-TEST(ExpressionTest, UnaryWithCommaAsTuple) {
+TEST_F(ExpressionTest, UnaryWithCommaAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)}},
       .has_trailing_comma = true};
 
-  Ptr<const Expression> tuple =
-      TupleExpressionFromParenContents(FakeSourceLoc(1), contents);
+  Ptr<const Expression> tuple = TupleExpressionFromParenContents(
+      PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
               ElementsAre(IntFieldNamed("0")));
 }
 
-TEST(ExpressionTest, BinaryAsExpression) {
+TEST_F(ExpressionTest, BinaryAsExpression) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)},
                    {.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(3), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(3), 42)}},
       .has_trailing_comma = true};
 
   Ptr<const Expression> expression =
-      ExpressionFromParenContents(FakeSourceLoc(1), contents);
+      ExpressionFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(expression->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
               ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
 }
 
-TEST(ExpressionTest, BinaryAsTuple) {
+TEST_F(ExpressionTest, BinaryAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(2), 42)},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(2), 42)},
                    {.name = std::nullopt,
-                    .term =
-                        global_arena->New<IntLiteral>(FakeSourceLoc(3), 42)}},
+                    .term = arena.New<IntLiteral>(FakeSourceLoc(3), 42)}},
       .has_trailing_comma = true};
 
-  Ptr<const Expression> tuple =
-      TupleExpressionFromParenContents(FakeSourceLoc(1), contents);
+  Ptr<const Expression> tuple = TupleExpressionFromParenContents(
+      PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
   EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),

+ 11 - 9
executable_semantics/ast/pattern.cpp

@@ -54,30 +54,31 @@ void Pattern::Print(llvm::raw_ostream& out) const {
   }
 }
 
-TuplePattern::TuplePattern(Ptr<const Expression> tuple_literal)
+TuplePattern::TuplePattern(Ptr<Arena> arena,
+                           Ptr<const Expression> tuple_literal)
     : Pattern(Kind::TuplePattern, tuple_literal->SourceLoc()) {
   const auto& tuple = cast<TupleLiteral>(*tuple_literal);
   for (const FieldInitializer& init : tuple.Fields()) {
-    fields.push_back(Field(
-        init.name, global_arena->New<ExpressionPattern>(init.expression)));
+    fields.push_back(
+        Field(init.name, arena->New<ExpressionPattern>(init.expression)));
   }
 }
 
-auto PatternFromParenContents(SourceLocation loc,
+auto PatternFromParenContents(Ptr<Arena> arena, SourceLocation loc,
                               const ParenContents<Pattern>& paren_contents)
     -> Ptr<const Pattern> {
   std::optional<Ptr<const Pattern>> single_term = paren_contents.SingleTerm();
   if (single_term.has_value()) {
     return *single_term;
   } else {
-    return TuplePatternFromParenContents(loc, paren_contents);
+    return TuplePatternFromParenContents(arena, loc, paren_contents);
   }
 }
 
-auto TuplePatternFromParenContents(SourceLocation loc,
+auto TuplePatternFromParenContents(Ptr<Arena> arena, SourceLocation loc,
                                    const ParenContents<Pattern>& paren_contents)
     -> Ptr<const TuplePattern> {
-  return global_arena->New<TuplePattern>(
+  return arena->New<TuplePattern>(
       loc, paren_contents.TupleElements<TuplePattern::Field>(loc));
 }
 
@@ -101,14 +102,15 @@ AlternativePattern::AlternativePattern(SourceLocation loc,
       alternative_name(RequireFieldAccess(alternative).Field()),
       arguments(arguments) {}
 
-auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)
+auto ParenExpressionToParenPattern(Ptr<Arena> arena,
+                                   const ParenContents<Expression>& contents)
     -> ParenContents<Pattern> {
   ParenContents<Pattern> result = {
       .elements = {}, .has_trailing_comma = contents.has_trailing_comma};
   for (const auto& element : contents.elements) {
     result.elements.push_back(
         {.name = element.name,
-         .term = global_arena->New<ExpressionPattern>(element.term)});
+         .term = arena->New<ExpressionPattern>(element.term)});
   }
   return result;
 }

+ 5 - 4
executable_semantics/ast/pattern.h

@@ -111,7 +111,7 @@ class TuplePattern : public Pattern {
   // ExpressionPattern.
   //
   // REQUIRES: tuple_literal->Tag() == Expression::Kind::TupleLiteral
-  explicit TuplePattern(Ptr<const Expression> tuple_literal);
+  TuplePattern(Ptr<Arena> arena, Ptr<const Expression> tuple_literal);
 
   static auto classof(const Pattern* pattern) -> bool {
     return pattern->Tag() == Kind::TuplePattern;
@@ -126,19 +126,20 @@ class TuplePattern : public Pattern {
 // Converts paren_contents to a Pattern, interpreting the parentheses as
 // grouping if their contents permit that interpretation, or as forming a
 // tuple otherwise.
-auto PatternFromParenContents(SourceLocation loc,
+auto PatternFromParenContents(Ptr<Arena> arena, SourceLocation loc,
                               const ParenContents<Pattern>& paren_contents)
     -> Ptr<const Pattern>;
 
 // Converts paren_contents to a TuplePattern, interpreting the parentheses as
 // forming a tuple.
-auto TuplePatternFromParenContents(SourceLocation loc,
+auto TuplePatternFromParenContents(Ptr<Arena> arena, SourceLocation loc,
                                    const ParenContents<Pattern>& paren_contents)
     -> Ptr<const TuplePattern>;
 
 // Converts `contents` to ParenContents<Pattern> by replacing each Expression
 // with an ExpressionPattern.
-auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)
+auto ParenExpressionToParenPattern(Ptr<Arena> arena,
+                                   const ParenContents<Expression>& contents)
     -> ParenContents<Pattern>;
 
 // A pattern that matches an alternative of a choice type.

+ 29 - 24
executable_semantics/ast/pattern_test.cpp

@@ -29,26 +29,31 @@ static auto FakeSourceLoc(int line_num) -> SourceLocation {
   return SourceLocation("<test>", line_num);
 }
 
-TEST(PatternTest, EmptyAsPattern) {
+class PatternTest : public ::testing::Test {
+ protected:
+  Arena arena;
+};
+
+TEST_F(PatternTest, EmptyAsPattern) {
   ParenContents<Pattern> contents = {.elements = {},
                                      .has_trailing_comma = false};
   Ptr<const Pattern> pattern =
-      PatternFromParenContents(FakeSourceLoc(1), contents);
+      PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1));
   ASSERT_TRUE(isa<TuplePattern>(*pattern));
   EXPECT_THAT(cast<TuplePattern>(*pattern).Fields(), IsEmpty());
 }
 
-TEST(PatternTest, EmptyAsTuplePattern) {
+TEST_F(PatternTest, EmptyAsTuplePattern) {
   ParenContents<Pattern> contents = {.elements = {},
                                      .has_trailing_comma = false};
   Ptr<const TuplePattern> tuple =
-      TuplePatternFromParenContents(FakeSourceLoc(1), contents);
+      TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   EXPECT_THAT(tuple->Fields(), IsEmpty());
 }
 
-TEST(PatternTest, UnaryNoCommaAsPattern) {
+TEST_F(PatternTest, UnaryNoCommaAsPattern) {
   // Equivalent to a code fragment like
   // ```
   // (
@@ -57,79 +62,79 @@ TEST(PatternTest, UnaryNoCommaAsPattern) {
   // ```
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = false};
 
   Ptr<const Pattern> pattern =
-      PatternFromParenContents(FakeSourceLoc(1), contents);
+      PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(2));
   ASSERT_TRUE(isa<AutoPattern>(*pattern));
 }
 
-TEST(PatternTest, UnaryNoCommaAsTuplePattern) {
+TEST_F(PatternTest, UnaryNoCommaAsTuplePattern) {
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = false};
 
   Ptr<const TuplePattern> tuple =
-      TuplePatternFromParenContents(FakeSourceLoc(1), contents);
+      TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0")));
 }
 
-TEST(PatternTest, UnaryWithCommaAsPattern) {
+TEST_F(PatternTest, UnaryWithCommaAsPattern) {
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = true};
 
   Ptr<const Pattern> pattern =
-      PatternFromParenContents(FakeSourceLoc(1), contents);
+      PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1));
   ASSERT_TRUE(isa<TuplePattern>(*pattern));
   EXPECT_THAT(cast<TuplePattern>(*pattern).Fields(),
               ElementsAre(AutoFieldNamed("0")));
 }
 
-TEST(PatternTest, UnaryWithCommaAsTuplePattern) {
+TEST_F(PatternTest, UnaryWithCommaAsTuplePattern) {
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = true};
 
   Ptr<const TuplePattern> tuple =
-      TuplePatternFromParenContents(FakeSourceLoc(1), contents);
+      TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   EXPECT_THAT(tuple->Fields(), ElementsAre(AutoFieldNamed("0")));
 }
 
-TEST(PatternTest, BinaryAsPattern) {
+TEST_F(PatternTest, BinaryAsPattern) {
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))},
                    {.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = true};
 
   Ptr<const Pattern> pattern =
-      PatternFromParenContents(FakeSourceLoc(1), contents);
+      PatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(pattern->SourceLoc(), FakeSourceLoc(1));
   ASSERT_TRUE(isa<TuplePattern>(*pattern));
   EXPECT_THAT(cast<TuplePattern>(*pattern).Fields(),
               ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1")));
 }
 
-TEST(PatternTest, BinaryAsTuplePattern) {
+TEST_F(PatternTest, BinaryAsTuplePattern) {
   ParenContents<Pattern> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))},
                    {.name = std::nullopt,
-                    .term = global_arena->New<AutoPattern>(FakeSourceLoc(2))}},
+                    .term = arena.New<AutoPattern>(FakeSourceLoc(2))}},
       .has_trailing_comma = true};
 
   Ptr<const TuplePattern> tuple =
-      TuplePatternFromParenContents(FakeSourceLoc(1), contents);
+      TuplePatternFromParenContents(PtrTo(arena), FakeSourceLoc(1), contents);
   EXPECT_EQ(tuple->SourceLoc(), FakeSourceLoc(1));
   EXPECT_THAT(tuple->Fields(),
               ElementsAre(AutoFieldNamed("0"), AutoFieldNamed("1")));

+ 2 - 2
executable_semantics/ast/statement.h

@@ -135,8 +135,8 @@ class If : public Statement {
 
 class Return : public Statement {
  public:
-  explicit Return(SourceLocation loc)
-      : Return(loc, global_arena->New<TupleLiteral>(loc), true) {}
+  Return(Ptr<Arena> arena, SourceLocation loc)
+      : Return(loc, arena->New<TupleLiteral>(loc), true) {}
   Return(SourceLocation loc, Ptr<const Expression> exp, bool is_omitted_exp)
       : Statement(Kind::Return, loc),
         exp(exp),

+ 0 - 2
executable_semantics/common/BUILD

@@ -6,11 +6,9 @@ package(default_visibility = ["//executable_semantics:__subpackages__"])
 
 cc_library(
     name = "arena",
-    srcs = ["arena.cpp"],
     hdrs = ["arena.h"],
     deps = [
         ":ptr",
-        "@llvm-project//llvm:Support",
     ],
 )
 

+ 0 - 11
executable_semantics/common/arena.cpp

@@ -1,11 +0,0 @@
-// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
-// Exceptions. See /LICENSE for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-
-#include "executable_semantics/common/arena.h"
-
-namespace Carbon {
-
-llvm::ManagedStatic<Arena> global_arena;
-
-}  // namespace Carbon

+ 0 - 3
executable_semantics/common/arena.h

@@ -9,7 +9,6 @@
 #include <vector>
 
 #include "executable_semantics/common/ptr.h"
-#include "llvm/Support/ManagedStatic.h"
 
 namespace Carbon {
 
@@ -51,8 +50,6 @@ class Arena {
   std::vector<std::unique_ptr<ArenaEntry>> arena;
 };
 
-extern llvm::ManagedStatic<Arena> global_arena;
-
 }  // namespace Carbon
 
 #endif  // EXECUTABLE_SEMANTICS_COMMON_ARENA_H_

+ 5 - 0
executable_semantics/common/ptr.h

@@ -39,6 +39,11 @@ class Ptr {
   T* ptr;
 };
 
+template <typename T>
+auto PtrTo(T& obj) -> Ptr<T> {
+  return Ptr<T>(&obj);
+}
+
 }  // namespace Carbon
 
 #endif  // EXECUTABLE_SEMANTICS_COMMON_PTR_H_

+ 3 - 2
executable_semantics/interpreter/dictionary.h

@@ -60,7 +60,7 @@ class Dictionary {
   };
 
   // Create an empty dictionary.
-  Dictionary() {}
+  explicit Dictionary(Ptr<Arena> arena) : arena(arena) {}
 
   // Return the value associated with the given key.
   // Time complexity: O(n) where n is the number of times
@@ -77,7 +77,7 @@ class Dictionary {
   // Associate the value v with key k in the dictionary.
   // Time complexity: O(1).
   auto Set(const K& k, const V& v) -> void {
-    head = global_arena->New<Node>(std::make_pair(k, v), head);
+    head = arena->New<Node>(std::make_pair(k, v), head);
   }
 
   bool IsEmpty() { return !head; }
@@ -91,6 +91,7 @@ class Dictionary {
 
  private:
   std::optional<Ptr<Node>> head;
+  Ptr<Arena> arena;
 };
 
 }  // namespace Carbon

+ 19 - 20
executable_semantics/interpreter/exec_program.cpp

@@ -15,30 +15,29 @@ namespace Carbon {
 
 // Adds builtins, currently only Print(). Note Print() is experimental, not
 // standardized, but is made available for printing state in tests.
-static void AddIntrinsics(std::vector<Ptr<const Declaration>>* declarations) {
+static void AddIntrinsics(Ptr<Arena> arena,
+                          std::vector<Ptr<const Declaration>>* declarations) {
   SourceLocation loc("<intrinsic>", 0);
   std::vector<TuplePattern::Field> print_fields = {TuplePattern::Field(
-      "0", global_arena->New<BindingPattern>(
-               loc, "format_str",
-               global_arena->New<ExpressionPattern>(
-                   global_arena->New<StringTypeLiteral>(loc))))};
+      "0",
+      arena->New<BindingPattern>(
+          loc, "format_str",
+          arena->New<ExpressionPattern>(arena->New<StringTypeLiteral>(loc))))};
   auto print_return =
-      global_arena->New<Return>(loc,
-                                global_arena->New<IntrinsicExpression>(
-                                    IntrinsicExpression::IntrinsicKind::Print),
-                                false);
-  auto print = global_arena->New<FunctionDeclaration>(
-      global_arena->New<FunctionDefinition>(
-          loc, "Print", std::vector<GenericBinding>(),
-          global_arena->New<TuplePattern>(loc, print_fields),
-          global_arena->New<ExpressionPattern>(
-              global_arena->New<TupleLiteral>(loc)),
-          /*is_omitted_return_type=*/false, print_return));
+      arena->New<Return>(loc,
+                         arena->New<IntrinsicExpression>(
+                             IntrinsicExpression::IntrinsicKind::Print),
+                         false);
+  auto print = arena->New<FunctionDeclaration>(arena->New<FunctionDefinition>(
+      loc, "Print", std::vector<GenericBinding>(),
+      arena->New<TuplePattern>(loc, print_fields),
+      arena->New<ExpressionPattern>(arena->New<TupleLiteral>(loc)),
+      /*is_omitted_return_type=*/false, print_return));
   declarations->insert(declarations->begin(), print);
 }
 
-void ExecProgram(AST ast) {
-  AddIntrinsics(&ast.declarations);
+void ExecProgram(Ptr<Arena> arena, AST ast) {
+  AddIntrinsics(arena, &ast.declarations);
   if (tracing_output) {
     llvm::outs() << "********** source program **********\n";
     for (const auto decl : ast.declarations) {
@@ -46,7 +45,7 @@ void ExecProgram(AST ast) {
     }
     llvm::outs() << "********** type checking **********\n";
   }
-  TypeChecker type_checker;
+  TypeChecker type_checker(arena);
   TypeChecker::TypeCheckContext p = type_checker.TopLevel(ast.declarations);
   TypeEnv top = p.types;
   Env ct_top = p.values;
@@ -62,7 +61,7 @@ void ExecProgram(AST ast) {
     }
     llvm::outs() << "********** starting execution **********\n";
   }
-  int result = Interpreter().InterpProgram(new_decls);
+  int result = Interpreter(arena).InterpProgram(new_decls);
   llvm::outs() << "result: " << result << "\n";
 }
 

+ 1 - 1
executable_semantics/interpreter/exec_program.h

@@ -14,7 +14,7 @@
 namespace Carbon {
 
 // Runs the top-level declaration list.
-void ExecProgram(AST ast);
+void ExecProgram(Ptr<Arena> arena, AST ast);
 
 }  // namespace Carbon
 

+ 12 - 12
executable_semantics/interpreter/heap.cpp

@@ -14,33 +14,33 @@ auto Heap::AllocateValue(Ptr<const Value> v) -> Address {
   // ensures that we don't do anything else in between, which is really bad!
   // Consider whether to include a copy of the input v in this function
   // or to leave it up to the caller.
-  Address a(values_.size());
-  values_.push_back(v);
-  alive_.push_back(true);
+  Address a(values.size());
+  values.push_back(v);
+  alive.push_back(true);
   return a;
 }
 
 auto Heap::Read(const Address& a, SourceLocation loc) -> Ptr<const Value> {
   this->CheckAlive(a, loc);
-  return values_[a.index]->GetField(a.field_path, loc);
+  return values[a.index]->GetField(arena, a.field_path, loc);
 }
 
 void Heap::Write(const Address& a, Ptr<const Value> v, SourceLocation loc) {
   this->CheckAlive(a, loc);
-  values_[a.index] = values_[a.index]->SetField(a.field_path, v, loc);
+  values[a.index] = values[a.index]->SetField(arena, a.field_path, v, loc);
 }
 
 void Heap::CheckAlive(const Address& address, SourceLocation loc) {
-  if (!alive_[address.index]) {
+  if (!alive[address.index]) {
     FATAL_RUNTIME_ERROR(loc) << "undefined behavior: access to dead value "
-                             << *values_[address.index];
+                             << *values[address.index];
   }
 }
 
 void Heap::Deallocate(const Address& address) {
   CHECK(address.field_path.IsEmpty());
-  if (alive_[address.index]) {
-    alive_[address.index] = false;
+  if (alive[address.index]) {
+    alive[address.index] = false;
   } else {
     FATAL_RUNTIME_ERROR_NO_LINE() << "deallocating an already dead value";
   }
@@ -48,17 +48,17 @@ void Heap::Deallocate(const Address& address) {
 
 void Heap::Print(llvm::raw_ostream& out) const {
   llvm::ListSeparator sep;
-  for (size_t i = 0; i < values_.size(); ++i) {
+  for (size_t i = 0; i < values.size(); ++i) {
     out << sep;
     PrintAddress(Address(i), out);
   }
 }
 
 void Heap::PrintAddress(const Address& a, llvm::raw_ostream& out) const {
-  if (!alive_[a.index]) {
+  if (!alive[a.index]) {
     out << "!!";
   }
-  out << *values_[a.index];
+  out << *values[a.index];
 }
 
 }  // namespace Carbon

+ 4 - 3
executable_semantics/interpreter/heap.h

@@ -18,7 +18,7 @@ namespace Carbon {
 class Heap {
  public:
   // Constructs an empty Heap.
-  Heap() = default;
+  explicit Heap(Ptr<Arena> arena) : arena(arena){};
 
   Heap(const Heap&) = delete;
   Heap& operator=(const Heap&) = delete;
@@ -49,8 +49,9 @@ class Heap {
   // Signal an error if the address is no longer alive.
   void CheckAlive(const Address& address, SourceLocation loc);
 
-  std::vector<Ptr<const Value>> values_;
-  std::vector<bool> alive_;
+  Ptr<Arena> arena;
+  std::vector<Ptr<const Value>> values;
+  std::vector<bool> alive;
 };
 
 }  // namespace Carbon

+ 137 - 147
executable_semantics/interpreter/interpreter.cpp

@@ -74,32 +74,33 @@ void Interpreter::PrintState(llvm::raw_ostream& out) {
   out << "\n}\n";
 }
 
-static auto EvalPrim(Operator op, const std::vector<Ptr<const Value>>& args,
-                     SourceLocation loc) -> Ptr<const Value> {
+auto Interpreter::EvalPrim(Operator op,
+                           const std::vector<Ptr<const Value>>& args,
+                           SourceLocation loc) -> Ptr<const Value> {
   switch (op) {
     case Operator::Neg:
-      return global_arena->New<IntValue>(-cast<IntValue>(*args[0]).Val());
+      return arena->New<IntValue>(-cast<IntValue>(*args[0]).Val());
     case Operator::Add:
-      return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() +
-                                         cast<IntValue>(*args[1]).Val());
+      return arena->New<IntValue>(cast<IntValue>(*args[0]).Val() +
+                                  cast<IntValue>(*args[1]).Val());
     case Operator::Sub:
-      return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() -
-                                         cast<IntValue>(*args[1]).Val());
+      return arena->New<IntValue>(cast<IntValue>(*args[0]).Val() -
+                                  cast<IntValue>(*args[1]).Val());
     case Operator::Mul:
-      return global_arena->New<IntValue>(cast<IntValue>(*args[0]).Val() *
-                                         cast<IntValue>(*args[1]).Val());
+      return arena->New<IntValue>(cast<IntValue>(*args[0]).Val() *
+                                  cast<IntValue>(*args[1]).Val());
     case Operator::Not:
-      return global_arena->New<BoolValue>(!cast<BoolValue>(*args[0]).Val());
+      return arena->New<BoolValue>(!cast<BoolValue>(*args[0]).Val());
     case Operator::And:
-      return global_arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() &&
-                                          cast<BoolValue>(*args[1]).Val());
+      return arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() &&
+                                   cast<BoolValue>(*args[1]).Val());
     case Operator::Or:
-      return global_arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() ||
-                                          cast<BoolValue>(*args[1]).Val());
+      return arena->New<BoolValue>(cast<BoolValue>(*args[0]).Val() ||
+                                   cast<BoolValue>(*args[1]).Val());
     case Operator::Eq:
-      return global_arena->New<BoolValue>(ValueEqual(args[0], args[1], loc));
+      return arena->New<BoolValue>(ValueEqual(args[0], args[1], loc));
     case Operator::Ptr:
-      return global_arena->New<PointerType>(args[0]);
+      return arena->New<PointerType>(args[0]);
     case Operator::Deref:
       FATAL() << "dereference not implemented yet";
   }
@@ -113,13 +114,11 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
       Env new_env = *env;
       // Bring the deduced parameters into scope.
       for (const auto& deduced : func_def.deduced_parameters) {
-        Address a =
-            heap.AllocateValue(global_arena->New<VariableType>(deduced.name));
+        Address a = heap.AllocateValue(arena->New<VariableType>(deduced.name));
         new_env.Set(deduced.name, a);
       }
       auto pt = InterpPattern(new_env, func_def.param_pattern);
-      auto f =
-          global_arena->New<FunctionValue>(func_def.name, pt, func_def.body);
+      auto f = arena->New<FunctionValue>(func_def.name, pt, func_def.body);
       Address a = heap.AllocateValue(f);
       env->Set(func_def.name, a);
       break;
@@ -135,14 +134,14 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
             Ptr<const BindingPattern> binding = cast<FieldMember>(*m).Binding();
             Ptr<const Expression> type_expression =
                 cast<ExpressionPattern>(*binding->Type()).Expression();
-            auto type = InterpExp(Env(), type_expression);
+            auto type = InterpExp(Env(arena), type_expression);
             fields.push_back(make_pair(*binding->Name(), type));
             break;
           }
         }
       }
-      auto st = global_arena->New<ClassType>(class_def.name, std::move(fields),
-                                             std::move(methods));
+      auto st = arena->New<ClassType>(class_def.name, std::move(fields),
+                                      std::move(methods));
       auto a = heap.AllocateValue(st);
       env->Set(class_def.name, a);
       break;
@@ -152,10 +151,10 @@ void Interpreter::InitEnv(const Declaration& d, Env* env) {
       const auto& choice = cast<ChoiceDeclaration>(d);
       VarValues alts;
       for (const auto& [name, signature] : choice.Alternatives()) {
-        auto t = InterpExp(Env(), signature);
+        auto t = InterpExp(Env(arena), signature);
         alts.push_back(make_pair(name, t));
       }
-      auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
+      auto ct = arena->New<ChoiceType>(choice.Name(), std::move(alts));
       auto a = heap.AllocateValue(ct);
       env->Set(choice.Name(), a);
       break;
@@ -194,8 +193,8 @@ void Interpreter::DeallocateLocals(Ptr<Frame> frame) {
   }
 }
 
-static Ptr<const Value> CreateTuple(Ptr<Action> act,
-                                    Ptr<const Expression> exp) {
+auto Interpreter::CreateTuple(Ptr<Action> act, Ptr<const Expression> exp)
+    -> Ptr<const Value> {
   //    { { (v1,...,vn) :: C, E, F} :: S, H}
   // -> { { `(v1,...,vn) :: C, E, F} :: S, H}
   const auto& tup_lit = cast<TupleLiteral>(*exp);
@@ -206,7 +205,7 @@ static Ptr<const Value> CreateTuple(Ptr<Action> act,
         {.name = tup_lit.Fields()[i].name, .value = act->Results()[i]});
   }
 
-  return global_arena->New<TupleValue>(std::move(elements));
+  return arena->New<TupleValue>(std::move(elements));
 }
 
 auto Interpreter::PatternMatch(Ptr<const Value> p, Ptr<const Value> v,
@@ -214,9 +213,9 @@ auto Interpreter::PatternMatch(Ptr<const Value> p, Ptr<const Value> v,
   switch (p->Tag()) {
     case Value::Kind::BindingPlaceholderValue: {
       const auto& placeholder = cast<BindingPlaceholderValue>(*p);
-      Env values;
+      Env values(arena);
       if (placeholder.Name().has_value()) {
-        Address a = heap.AllocateValue(CopyVal(v, loc));
+        Address a = heap.AllocateValue(CopyVal(arena, v, loc));
         values.Set(*placeholder.Name(), a);
       }
       return values;
@@ -231,7 +230,7 @@ auto Interpreter::PatternMatch(Ptr<const Value> p, Ptr<const Value> v,
                 << "arity mismatch in tuple pattern match:\n  pattern: "
                 << p_tup << "\n  value: " << v_tup;
           }
-          Env values;
+          Env values(arena);
           for (size_t i = 0; i < p_tup.Elements().size(); ++i) {
             if (p_tup.Elements()[i].name != v_tup.Elements()[i].name) {
               FATAL_PROGRAM_ERROR(loc)
@@ -294,10 +293,10 @@ auto Interpreter::PatternMatch(Ptr<const Value> p, Ptr<const Value> v,
     case Value::Kind::AutoType:
       // `auto` matches any type, without binding any new names. We rely
       // on the typechecker to ensure that `v` is a type.
-      return Env();
+      return Env(arena);
     default:
       if (ValueEqual(p, v, loc)) {
-        return Env();
+        return Env(arena);
       } else {
         return std::nullopt;
       }
@@ -308,7 +307,7 @@ void Interpreter::PatternAssignment(Ptr<const Value> pat, Ptr<const Value> val,
                                     SourceLocation loc) {
   switch (pat->Tag()) {
     case Value::Kind::PointerValue:
-      heap.Write(cast<PointerValue>(*pat).Val(), CopyVal(val, loc), loc);
+      heap.Write(cast<PointerValue>(*pat).Val(), CopyVal(arena, val, loc), loc);
       break;
     case Value::Kind::TupleValue: {
       switch (val->Tag()) {
@@ -371,14 +370,14 @@ auto Interpreter::StepLvalue() -> Transition {
       // -> { {E(x) :: C, E, F} :: S, H}
       Address pointer =
           GetFromEnv(exp->SourceLoc(), cast<IdentifierExpression>(*exp).Name());
-      Ptr<const Value> v = global_arena->New<PointerValue>(pointer);
+      Ptr<const Value> v = arena->New<PointerValue>(pointer);
       return Done{v};
     }
     case Expression::Kind::FieldAccessExpression: {
       if (act->Pos() == 0) {
         //    { {e.f :: C, E, F} :: S, H}
         // -> { e :: [].f :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<LValAction>(
+        return Spawn{arena->New<LValAction>(
             cast<FieldAccessExpression>(*exp).Aggregate())};
       } else {
         //    { v :: [].f :: C, E, F} :: S, H}
@@ -386,19 +385,19 @@ auto Interpreter::StepLvalue() -> Transition {
         Address aggregate = cast<PointerValue>(*act->Results()[0]).Val();
         Address field = aggregate.SubobjectAddress(
             cast<FieldAccessExpression>(*exp).Field());
-        return Done{global_arena->New<PointerValue>(field)};
+        return Done{arena->New<PointerValue>(field)};
       }
     }
     case Expression::Kind::IndexExpression: {
       if (act->Pos() == 0) {
         //    { {e[i] :: C, E, F} :: S, H}
         // -> { e :: [][i] :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<LValAction>(
-            cast<IndexExpression>(*exp).Aggregate())};
+        return Spawn{
+            arena->New<LValAction>(cast<IndexExpression>(*exp).Aggregate())};
 
       } else if (act->Pos() == 1) {
-        return Spawn{global_arena->New<ExpressionAction>(
-            cast<IndexExpression>(*exp).Offset())};
+        return Spawn{
+            arena->New<ExpressionAction>(cast<IndexExpression>(*exp).Offset())};
       } else {
         //    { v :: [][i] :: C, E, F} :: S, H}
         // -> { { &v[i] :: C, E, F} :: S, H }
@@ -406,7 +405,7 @@ auto Interpreter::StepLvalue() -> Transition {
         std::string f =
             std::to_string(cast<IntValue>(*act->Results()[1]).Val());
         Address field = aggregate.SubobjectAddress(f);
-        return Done{global_arena->New<PointerValue>(field)};
+        return Done{arena->New<PointerValue>(field)};
       }
     }
     case Expression::Kind::TupleLiteral: {
@@ -415,7 +414,7 @@ auto Interpreter::StepLvalue() -> Transition {
         // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
         Ptr<const Expression> e1 =
             cast<TupleLiteral>(*exp).Fields()[0].expression;
-        return Spawn{global_arena->New<LValAction>(e1)};
+        return Spawn{arena->New<LValAction>(e1)};
       } else if (act->Pos() !=
                  static_cast<int>(cast<TupleLiteral>(*exp).Fields().size())) {
         //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
@@ -424,7 +423,7 @@ auto Interpreter::StepLvalue() -> Transition {
         // H}
         Ptr<const Expression> elt =
             cast<TupleLiteral>(*exp).Fields()[act->Pos()].expression;
-        return Spawn{global_arena->New<LValAction>(elt)};
+        return Spawn{arena->New<LValAction>(elt)};
       } else {
         return Done{CreateTuple(act, exp)};
       }
@@ -458,11 +457,11 @@ auto Interpreter::StepExp() -> Transition {
       if (act->Pos() == 0) {
         //    { { e[i] :: C, E, F} :: S, H}
         // -> { { e :: [][i] :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<IndexExpression>(*exp).Aggregate())};
       } else if (act->Pos() == 1) {
-        return Spawn{global_arena->New<ExpressionAction>(
-            cast<IndexExpression>(*exp).Offset())};
+        return Spawn{
+            arena->New<ExpressionAction>(cast<IndexExpression>(*exp).Offset())};
       } else {
         //    { { v :: [][i] :: C, E, F} :: S, H}
         // -> { { v_i :: C, E, F} : S, H}
@@ -488,7 +487,7 @@ auto Interpreter::StepExp() -> Transition {
           // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
           Ptr<const Expression> e1 =
               cast<TupleLiteral>(*exp).Fields()[0].expression;
-          return Spawn{global_arena->New<ExpressionAction>(e1)};
+          return Spawn{arena->New<ExpressionAction>(e1)};
         } else {
           return Done{CreateTuple(act, exp)};
         }
@@ -500,7 +499,7 @@ auto Interpreter::StepExp() -> Transition {
         // H}
         Ptr<const Expression> elt =
             cast<TupleLiteral>(*exp).Fields()[act->Pos()].expression;
-        return Spawn{global_arena->New<ExpressionAction>(elt)};
+        return Spawn{arena->New<ExpressionAction>(elt)};
       } else {
         return Done{CreateTuple(act, exp)};
       }
@@ -510,12 +509,12 @@ auto Interpreter::StepExp() -> Transition {
       if (act->Pos() == 0) {
         //    { { e.f :: C, E, F} :: S, H}
         // -> { { e :: [].f :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(access.Aggregate())};
+        return Spawn{arena->New<ExpressionAction>(access.Aggregate())};
       } else {
         //    { { v :: [].f :: C, E, F} :: S, H}
         // -> { { v_f :: C, E, F} : S, H}
-        return Done{act->Results()[0]->GetField(FieldPath(access.Field()),
-                                                exp->SourceLoc())};
+        return Done{act->Results()[0]->GetField(
+            arena, FieldPath(access.Field()), exp->SourceLoc())};
       }
     }
     case Expression::Kind::IdentifierExpression: {
@@ -528,18 +527,18 @@ auto Interpreter::StepExp() -> Transition {
     case Expression::Kind::IntLiteral:
       CHECK(act->Pos() == 0);
       // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
-      return Done{global_arena->New<IntValue>(cast<IntLiteral>(*exp).Val())};
+      return Done{arena->New<IntValue>(cast<IntLiteral>(*exp).Val())};
     case Expression::Kind::BoolLiteral:
       CHECK(act->Pos() == 0);
       // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
-      return Done{global_arena->New<BoolValue>(cast<BoolLiteral>(*exp).Val())};
+      return Done{arena->New<BoolValue>(cast<BoolLiteral>(*exp).Val())};
     case Expression::Kind::PrimitiveOperatorExpression: {
       const auto& op = cast<PrimitiveOperatorExpression>(*exp);
       if (act->Pos() != static_cast<int>(op.Arguments().size())) {
         //    { {v :: op(vs,[],e,es) :: C, E, F} :: S, H}
         // -> { {e :: op(vs,v,[],es) :: C, E, F} :: S, H}
         Ptr<const Expression> arg = op.Arguments()[act->Pos()];
-        return Spawn{global_arena->New<ExpressionAction>(arg)};
+        return Spawn{arena->New<ExpressionAction>(arg)};
       } else {
         //    { {v :: op(vs,[]) :: C, E, F} :: S, H}
         // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H}
@@ -550,27 +549,29 @@ auto Interpreter::StepExp() -> Transition {
       if (act->Pos() == 0) {
         //    { {e1(e2) :: C, E, F} :: S, H}
         // -> { {e1 :: [](e2) :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<CallExpression>(*exp).Function())};
       } else if (act->Pos() == 1) {
         //    { { v :: [](e) :: C, E, F} :: S, H}
         // -> { { e :: v([]) :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<CallExpression>(*exp).Argument())};
       } else if (act->Pos() == 2) {
         //    { { v2 :: v1([]) :: C, E, F} :: S, H}
         // -> { {C',E',F'} :: {C, E, F} :: S, H}
         switch (act->Results()[0]->Tag()) {
           case Value::Kind::ClassType: {
-            Ptr<const Value> arg = CopyVal(act->Results()[1], exp->SourceLoc());
-            return Done{global_arena->New<StructValue>(act->Results()[0], arg)};
+            Ptr<const Value> arg =
+                CopyVal(arena, act->Results()[1], exp->SourceLoc());
+            return Done{arena->New<StructValue>(act->Results()[0], arg)};
           }
           case Value::Kind::AlternativeConstructorValue: {
             const auto& alt =
                 cast<AlternativeConstructorValue>(*act->Results()[0]);
-            Ptr<const Value> arg = CopyVal(act->Results()[1], exp->SourceLoc());
-            return Done{global_arena->New<AlternativeValue>(
-                alt.AltName(), alt.ChoiceName(), arg)};
+            Ptr<const Value> arg =
+                CopyVal(arena, act->Results()[1], exp->SourceLoc());
+            return Done{arena->New<AlternativeValue>(alt.AltName(),
+                                                     alt.ChoiceName(), arg)};
           }
           case Value::Kind::FunctionValue:
             return CallFunction{
@@ -602,45 +603,44 @@ auto Interpreter::StepExp() -> Transition {
 
     case Expression::Kind::IntTypeLiteral: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<IntType>()};
+      return Done{arena->New<IntType>()};
     }
     case Expression::Kind::BoolTypeLiteral: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<BoolType>()};
+      return Done{arena->New<BoolType>()};
     }
     case Expression::Kind::TypeTypeLiteral: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<TypeType>()};
+      return Done{arena->New<TypeType>()};
     }
     case Expression::Kind::FunctionTypeLiteral: {
       if (act->Pos() == 0) {
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<FunctionTypeLiteral>(*exp).Parameter())};
       } else if (act->Pos() == 1) {
         //    { { pt :: fn [] -> e :: C, E, F} :: S, H}
         // -> { { e :: fn pt -> []) :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<FunctionTypeLiteral>(*exp).ReturnType())};
       } else {
         //    { { rt :: fn pt -> [] :: C, E, F} :: S, H}
         // -> { fn pt -> rt :: {C, E, F} :: S, H}
-        return Done{global_arena->New<FunctionType>(
-            std::vector<GenericBinding>(), act->Results()[0],
-            act->Results()[1])};
+        return Done{arena->New<FunctionType>(std::vector<GenericBinding>(),
+                                             act->Results()[0],
+                                             act->Results()[1])};
       }
     }
     case Expression::Kind::ContinuationTypeLiteral: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<ContinuationType>()};
+      return Done{arena->New<ContinuationType>()};
     }
     case Expression::Kind::StringLiteral:
       CHECK(act->Pos() == 0);
       // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
-      return Done{
-          global_arena->New<StringValue>(cast<StringLiteral>(*exp).Val())};
+      return Done{arena->New<StringValue>(cast<StringLiteral>(*exp).Val())};
     case Expression::Kind::StringTypeLiteral: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<StringType>()};
+      return Done{arena->New<StringType>()};
     }
   }  // switch (exp->Tag)
 }
@@ -655,15 +655,15 @@ auto Interpreter::StepPattern() -> Transition {
   switch (pattern->Tag()) {
     case Pattern::Kind::AutoPattern: {
       CHECK(act->Pos() == 0);
-      return Done{global_arena->New<AutoType>()};
+      return Done{arena->New<AutoType>()};
     }
     case Pattern::Kind::BindingPattern: {
       const auto& binding = cast<BindingPattern>(*pattern);
       if (act->Pos() == 0) {
-        return Spawn{global_arena->New<PatternAction>(binding.Type())};
+        return Spawn{arena->New<PatternAction>(binding.Type())};
       } else {
-        return Done{global_arena->New<BindingPlaceholderValue>(
-            binding.Name(), act->Results()[0])};
+        return Done{arena->New<BindingPlaceholderValue>(binding.Name(),
+                                                        act->Results()[0])};
       }
     }
     case Pattern::Kind::TuplePattern: {
@@ -673,7 +673,7 @@ auto Interpreter::StepPattern() -> Transition {
           return Done{TupleValue::Empty()};
         } else {
           Ptr<const Pattern> p1 = tuple.Fields()[0].pattern;
-          return Spawn{(global_arena->New<PatternAction>(p1))};
+          return Spawn{(arena->New<PatternAction>(p1))};
         }
       } else if (act->Pos() != static_cast<int>(tuple.Fields().size())) {
         //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
@@ -681,33 +681,32 @@ auto Interpreter::StepPattern() -> Transition {
         // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
         // H}
         Ptr<const Pattern> elt = tuple.Fields()[act->Pos()].pattern;
-        return Spawn{global_arena->New<PatternAction>(elt)};
+        return Spawn{arena->New<PatternAction>(elt)};
       } else {
         std::vector<TupleElement> elements;
         for (size_t i = 0; i < tuple.Fields().size(); ++i) {
           elements.push_back(
               {.name = tuple.Fields()[i].name, .value = act->Results()[i]});
         }
-        return Done{global_arena->New<TupleValue>(std::move(elements))};
+        return Done{arena->New<TupleValue>(std::move(elements))};
       }
     }
     case Pattern::Kind::AlternativePattern: {
       const auto& alternative = cast<AlternativePattern>(*pattern);
       if (act->Pos() == 0) {
-        return Spawn{
-            global_arena->New<ExpressionAction>(alternative.ChoiceType())};
+        return Spawn{arena->New<ExpressionAction>(alternative.ChoiceType())};
       } else if (act->Pos() == 1) {
-        return Spawn{global_arena->New<PatternAction>(alternative.Arguments())};
+        return Spawn{arena->New<PatternAction>(alternative.Arguments())};
       } else {
         CHECK(act->Pos() == 2);
         const auto& choice_type = cast<ChoiceType>(*act->Results()[0]);
-        return Done{global_arena->New<AlternativeValue>(
-            alternative.AlternativeName(), choice_type.Name(),
-            act->Results()[1])};
+        return Done{arena->New<AlternativeValue>(alternative.AlternativeName(),
+                                                 choice_type.Name(),
+                                                 act->Results()[1])};
       }
     }
     case Pattern::Kind::ExpressionPattern:
-      return Delegate{global_arena->New<ExpressionAction>(
+      return Delegate{arena->New<ExpressionAction>(
           cast<ExpressionPattern>(*pattern).Expression())};
   }
 }
@@ -756,8 +755,8 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { { (match (e) ...) :: C, E, F} :: S, H}
         // -> { { e :: (match ([]) ...) :: C, E, F} :: S, H}
-        frame->scopes.Push(global_arena->New<Scope>(CurrentEnv()));
-        return Spawn{global_arena->New<ExpressionAction>(match_stmt.Exp())};
+        frame->scopes.Push(arena->New<Scope>(CurrentEnv()));
+        return Spawn{arena->New<ExpressionAction>(match_stmt.Exp())};
       } else {
         // Regarding act->Pos():
         // * odd: start interpreting the pattern of a clause
@@ -780,7 +779,7 @@ auto Interpreter::StepStmt() -> Transition {
           // start interpreting the pattern of the clause
           //    { {v :: (match ([]) ...) :: C, E, F} :: S, H}
           // -> { {pi :: (match ([]) ...) :: C, E, F} :: S, H}
-          return Spawn{global_arena->New<PatternAction>(c.first)};
+          return Spawn{arena->New<PatternAction>(c.first)};
         } else {  // try to match
           auto v = act->Results()[0];
           auto pat = act->Results()[clause_num + 1];
@@ -793,7 +792,7 @@ auto Interpreter::StepStmt() -> Transition {
               frame->scopes.Top()->values.Set(name, value);
               frame->scopes.Top()->locals.push_back(name);
             }
-            return Spawn{global_arena->New<StatementAction>(c.second)};
+            return Spawn{arena->New<StatementAction>(c.second)};
           } else {
             return RunAgain{};
           }
@@ -805,13 +804,11 @@ auto Interpreter::StepStmt() -> Transition {
         //    { { (while (e) s) :: C, E, F} :: S, H}
         // -> { { e :: (while ([]) s) :: C, E, F} :: S, H}
         act->Clear();
-        return Spawn{
-            global_arena->New<ExpressionAction>(cast<While>(*stmt).Cond())};
+        return Spawn{arena->New<ExpressionAction>(cast<While>(*stmt).Cond())};
       } else if (cast<BoolValue>(*act->Results().back()).Val()) {
         //    { {true :: (while ([]) s) :: C, E, F} :: S, H}
         // -> { { s :: (while (e) s) :: C, E, F } :: S, H}
-        return Spawn{
-            global_arena->New<StatementAction>(cast<While>(*stmt).Body())};
+        return Spawn{arena->New<StatementAction>(cast<While>(*stmt).Body())};
       } else {
         //    { {false :: (while ([]) s) :: C, E, F} :: S, H}
         // -> { { C, E, F } :: S, H}
@@ -846,8 +843,8 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         const Block& block = cast<Block>(*stmt);
         if (block.Stmt()) {
-          frame->scopes.Push(global_arena->New<Scope>(CurrentEnv()));
-          return Spawn{global_arena->New<StatementAction>(*block.Stmt())};
+          frame->scopes.Push(arena->New<Scope>(CurrentEnv()));
+          return Spawn{arena->New<StatementAction>(*block.Stmt())};
         } else {
           return Done{};
         }
@@ -862,11 +859,11 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { {(var x = e) :: C, E, F} :: S, H}
         // -> { {e :: (var x = []) :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<VariableDefinition>(*stmt).Init())};
       } else if (act->Pos() == 1) {
-        return Spawn{global_arena->New<PatternAction>(
-            cast<VariableDefinition>(*stmt).Pat())};
+        return Spawn{
+            arena->New<PatternAction>(cast<VariableDefinition>(*stmt).Pat())};
       } else {
         //    { { v :: (x = []) :: C, E, F} :: S, H}
         // -> { { C, E(x := a), F} :: S, H(a := copy(v))}
@@ -887,7 +884,7 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { {e :: C, E, F} :: S, H}
         // -> { {e :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<ExpressionAction>(
+        return Spawn{arena->New<ExpressionAction>(
             cast<ExpressionStatement>(*stmt).Exp())};
       } else {
         return Done{};
@@ -896,12 +893,11 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { {(lv = e) :: C, E, F} :: S, H}
         // -> { {lv :: ([] = e) :: C, E, F} :: S, H}
-        return Spawn{global_arena->New<LValAction>(cast<Assign>(*stmt).Lhs())};
+        return Spawn{arena->New<LValAction>(cast<Assign>(*stmt).Lhs())};
       } else if (act->Pos() == 1) {
         //    { { a :: ([] = e) :: C, E, F} :: S, H}
         // -> { { e :: (a = []) :: C, E, F} :: S, H}
-        return Spawn{
-            global_arena->New<ExpressionAction>(cast<Assign>(*stmt).Rhs())};
+        return Spawn{arena->New<ExpressionAction>(cast<Assign>(*stmt).Rhs())};
       } else {
         //    { { v :: (a = []) :: C, E, F} :: S, H}
         // -> { { C, E, F} :: S, H(a := v)}
@@ -914,20 +910,19 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { {(if (e) then_stmt else else_stmt) :: C, E, F} :: S, H}
         // -> { { e :: (if ([]) then_stmt else else_stmt) :: C, E, F} :: S, H}
-        return Spawn{
-            global_arena->New<ExpressionAction>(cast<If>(*stmt).Cond())};
+        return Spawn{arena->New<ExpressionAction>(cast<If>(*stmt).Cond())};
       } else if (cast<BoolValue>(*act->Results()[0]).Val()) {
         //    { {true :: if ([]) then_stmt else else_stmt :: C, E, F} ::
         //      S, H}
         // -> { { then_stmt :: C, E, F } :: S, H}
         return Delegate{
-            global_arena->New<StatementAction>(cast<If>(*stmt).ThenStmt())};
+            arena->New<StatementAction>(cast<If>(*stmt).ThenStmt())};
       } else if (cast<If>(*stmt).ElseStmt()) {
         //    { {false :: if ([]) then_stmt else else_stmt :: C, E, F} ::
         //      S, H}
         // -> { { else_stmt :: C, E, F } :: S, H}
         return Delegate{
-            global_arena->New<StatementAction>(*cast<If>(*stmt).ElseStmt())};
+            arena->New<StatementAction>(*cast<If>(*stmt).ElseStmt())};
       } else {
         return Done{};
       }
@@ -935,13 +930,12 @@ auto Interpreter::StepStmt() -> Transition {
       if (act->Pos() == 0) {
         //    { {return e :: C, E, F} :: S, H}
         // -> { {e :: return [] :: C, E, F} :: S, H}
-        return Spawn{
-            global_arena->New<ExpressionAction>(cast<Return>(*stmt).Exp())};
+        return Spawn{arena->New<ExpressionAction>(cast<Return>(*stmt).Exp())};
       } else {
         //    { {v :: return [] :: C, E, F} :: {C', E', F'} :: S, H}
         // -> { {v :: C', E', F'} :: S, H}
         Ptr<const Value> ret_val =
-            CopyVal(act->Results()[0], stmt->SourceLoc());
+            CopyVal(arena, act->Results()[0], stmt->SourceLoc());
         return UnwindFunctionCall{ret_val};
       }
     case Statement::Kind::Sequence: {
@@ -949,11 +943,11 @@ auto Interpreter::StepStmt() -> Transition {
       // -> { { s1 :: s2 :: C, E, F} :: S, H}
       const Sequence& seq = cast<Sequence>(*stmt);
       if (act->Pos() == 0) {
-        return Spawn{global_arena->New<StatementAction>(seq.Stmt())};
+        return Spawn{arena->New<StatementAction>(seq.Stmt())};
       } else {
         if (seq.Next()) {
-          return Delegate{global_arena->New<StatementAction>(
-              *cast<Sequence>(*stmt).Next())};
+          return Delegate{
+              arena->New<StatementAction>(*cast<Sequence>(*stmt).Next())};
         } else {
           return Done{};
         }
@@ -963,16 +957,15 @@ auto Interpreter::StepStmt() -> Transition {
       CHECK(act->Pos() == 0);
       // Create a continuation object by creating a frame similar the
       // way one is created in a function call.
-      auto scopes = Stack<Ptr<Scope>>(global_arena->New<Scope>(CurrentEnv()));
+      auto scopes = Stack<Ptr<Scope>>(arena->New<Scope>(CurrentEnv()));
       Stack<Ptr<Action>> todo;
-      todo.Push(global_arena->New<StatementAction>(
-          global_arena->New<Return>(stmt->SourceLoc())));
-      todo.Push(
-          global_arena->New<StatementAction>(cast<Continuation>(*stmt).Body()));
+      todo.Push(arena->New<StatementAction>(
+          arena->New<Return>(arena, stmt->SourceLoc())));
+      todo.Push(arena->New<StatementAction>(cast<Continuation>(*stmt).Body()));
       auto continuation_frame =
-          global_arena->New<Frame>("__continuation", scopes, todo);
+          arena->New<Frame>("__continuation", scopes, todo);
       Address continuation_address =
-          heap.AllocateValue(global_arena->New<ContinuationValue>(
+          heap.AllocateValue(arena->New<ContinuationValue>(
               std::vector<Ptr<Frame>>({continuation_frame})));
       // Store the continuation's address in the frame.
       continuation_frame->continuation = continuation_address;
@@ -987,16 +980,15 @@ auto Interpreter::StepStmt() -> Transition {
     case Statement::Kind::Run:
       if (act->Pos() == 0) {
         // Evaluate the argument of the run statement.
-        return Spawn{
-            global_arena->New<ExpressionAction>(cast<Run>(*stmt).Argument())};
+        return Spawn{arena->New<ExpressionAction>(cast<Run>(*stmt).Argument())};
       } else {
         frame->todo.Pop(1);
         // Push an expression statement action to ignore the result
         // value from the continuation.
-        auto ignore_result = global_arena->New<StatementAction>(
-            global_arena->New<ExpressionStatement>(
+        auto ignore_result =
+            arena->New<StatementAction>(arena->New<ExpressionStatement>(
                 stmt->SourceLoc(),
-                global_arena->New<TupleLiteral>(stmt->SourceLoc())));
+                arena->New<TupleLiteral>(stmt->SourceLoc())));
         frame->todo.Push(ignore_result);
         // Push the continuation onto the current stack.
         const std::vector<Ptr<Frame>>& continuation_vector =
@@ -1017,8 +1009,7 @@ auto Interpreter::StepStmt() -> Transition {
       } while (paused.back()->continuation == std::nullopt);
       // Update the continuation with the paused stack.
       heap.Write(*paused.back()->continuation,
-                 global_arena->New<ContinuationValue>(paused),
-                 stmt->SourceLoc());
+                 arena->New<ContinuationValue>(paused), stmt->SourceLoc());
       return ManualTransition{};
   }
 }
@@ -1096,11 +1087,13 @@ class Interpreter::DoTransition {
       values.Set(name, value);
       params.push_back(name);
     }
-    auto scopes = Stack<Ptr<Scope>>(global_arena->New<Scope>(values, params));
+    auto scopes =
+        Stack<Ptr<Scope>>(interpreter->arena->New<Scope>(values, params));
     CHECK(call.function->Body()) << "Calling a function that's missing a body";
     auto todo = Stack<Ptr<Action>>(
-        global_arena->New<StatementAction>(*call.function->Body()));
-    auto frame = global_arena->New<Frame>(call.function->Name(), scopes, todo);
+        interpreter->arena->New<StatementAction>(*call.function->Body()));
+    auto frame =
+        interpreter->arena->New<Frame>(call.function->Name(), scopes, todo);
     interpreter->stack.Push(frame);
   }
 
@@ -1149,13 +1142,12 @@ auto Interpreter::InterpProgram(const std::vector<Ptr<const Declaration>>& fs)
 
   SourceLocation loc("<InterpProgram()>", 0);
 
-  Ptr<const Expression> arg = global_arena->New<TupleLiteral>(loc);
-  Ptr<const Expression> call_main = global_arena->New<CallExpression>(
-      loc, global_arena->New<IdentifierExpression>(loc, "main"), arg);
-  auto todo =
-      Stack<Ptr<Action>>(global_arena->New<ExpressionAction>(call_main));
-  auto scopes = Stack<Ptr<Scope>>(global_arena->New<Scope>(globals));
-  stack = Stack<Ptr<Frame>>(global_arena->New<Frame>("top", scopes, todo));
+  Ptr<const Expression> arg = arena->New<TupleLiteral>(loc);
+  Ptr<const Expression> call_main = arena->New<CallExpression>(
+      loc, arena->New<IdentifierExpression>(loc, "main"), arg);
+  auto todo = Stack<Ptr<Action>>(arena->New<ExpressionAction>(call_main));
+  auto scopes = Stack<Ptr<Scope>>(arena->New<Scope>(globals));
+  stack = Stack<Ptr<Frame>>(arena->New<Frame>("top", scopes, todo));
 
   if (tracing_output) {
     llvm::outs() << "********** calling main function **********\n";
@@ -1176,10 +1168,9 @@ auto Interpreter::InterpExp(Env values, Ptr<const Expression> e)
   CHECK(program_value == std::nullopt);
   auto program_value_guard =
       llvm::make_scope_exit([&] { program_value = std::nullopt; });
-  auto todo = Stack<Ptr<Action>>(global_arena->New<ExpressionAction>(e));
-  auto scopes = Stack<Ptr<Scope>>(global_arena->New<Scope>(values));
-  stack =
-      Stack<Ptr<Frame>>(global_arena->New<Frame>("InterpExp", scopes, todo));
+  auto todo = Stack<Ptr<Action>>(arena->New<ExpressionAction>(e));
+  auto scopes = Stack<Ptr<Scope>>(arena->New<Scope>(values));
+  stack = Stack<Ptr<Frame>>(arena->New<Frame>("InterpExp", scopes, todo));
 
   while (stack.Count() > 1 || !stack.Top()->todo.IsEmpty()) {
     Step();
@@ -1193,10 +1184,9 @@ auto Interpreter::InterpPattern(Env values, Ptr<const Pattern> p)
   CHECK(program_value == std::nullopt);
   auto program_value_guard =
       llvm::make_scope_exit([&] { program_value = std::nullopt; });
-  auto todo = Stack<Ptr<Action>>(global_arena->New<PatternAction>(p));
-  auto scopes = Stack<Ptr<Scope>>(global_arena->New<Scope>(values));
-  stack = Stack<Ptr<Frame>>(
-      global_arena->New<Frame>("InterpPattern", scopes, todo));
+  auto todo = Stack<Ptr<Action>>(arena->New<PatternAction>(p));
+  auto scopes = Stack<Ptr<Scope>>(arena->New<Scope>(values));
+  stack = Stack<Ptr<Frame>>(arena->New<Frame>("InterpPattern", scopes, todo));
 
   while (stack.Count() > 1 || !stack.Top()->todo.IsEmpty()) {
     Step();

+ 11 - 0
executable_semantics/interpreter/interpreter.h

@@ -24,6 +24,9 @@ using Env = Dictionary<std::string, Address>;
 
 class Interpreter {
  public:
+  explicit Interpreter(Ptr<Arena> arena)
+      : arena(arena), globals(arena), heap(arena) {}
+
   // Interpret the whole program.
   auto InterpProgram(const std::vector<Ptr<const Declaration>>& fs) -> int;
 
@@ -130,11 +133,19 @@ class Interpreter {
   void DeallocateScope(Ptr<Scope> scope);
   void DeallocateLocals(Ptr<Frame> frame);
 
+  auto CreateTuple(Ptr<Action> act, Ptr<const Expression> exp)
+      -> Ptr<const Value>;
+
+  auto EvalPrim(Operator op, const std::vector<Ptr<const Value>>& args,
+                SourceLocation loc) -> Ptr<const Value>;
+
   void PatternAssignment(Ptr<const Value> pat, Ptr<const Value> val,
                          SourceLocation loc);
 
   void PrintState(llvm::raw_ostream& out);
 
+  Ptr<Arena> arena;
+
   // Globally-defined entities, such as functions, structs, or choices.
   Env globals;
 

+ 123 - 145
executable_semantics/interpreter/type_checker.cpp

@@ -50,21 +50,20 @@ static void ExpectPointerType(SourceLocation loc, const std::string& context,
   }
 }
 
-// Reify type to type expression.
-static auto ReifyType(Ptr<const Value> t, SourceLocation loc)
+auto TypeChecker::ReifyType(Ptr<const Value> t, SourceLocation loc)
     -> Ptr<const Expression> {
   switch (t->Tag()) {
     case Value::Kind::IntType:
-      return global_arena->New<IntTypeLiteral>(loc);
+      return arena->New<IntTypeLiteral>(loc);
     case Value::Kind::BoolType:
-      return global_arena->New<BoolTypeLiteral>(loc);
+      return arena->New<BoolTypeLiteral>(loc);
     case Value::Kind::TypeType:
-      return global_arena->New<TypeTypeLiteral>(loc);
+      return arena->New<TypeTypeLiteral>(loc);
     case Value::Kind::ContinuationType:
-      return global_arena->New<ContinuationTypeLiteral>(loc);
+      return arena->New<ContinuationTypeLiteral>(loc);
     case Value::Kind::FunctionType: {
       const auto& fn_type = cast<FunctionType>(*t);
-      return global_arena->New<FunctionTypeLiteral>(
+      return arena->New<FunctionTypeLiteral>(
           loc, ReifyType(fn_type.Param(), loc), ReifyType(fn_type.Ret(), loc),
           /*is_omitted_return_type=*/false);
     }
@@ -74,24 +73,22 @@ static auto ReifyType(Ptr<const Value> t, SourceLocation loc)
         args.push_back(
             FieldInitializer(field.name, ReifyType(field.value, loc)));
       }
-      return global_arena->New<TupleLiteral>(loc, args);
+      return arena->New<TupleLiteral>(loc, args);
     }
     case Value::Kind::ClassType:
-      return global_arena->New<IdentifierExpression>(
-          loc, cast<ClassType>(*t).Name());
+      return arena->New<IdentifierExpression>(loc, cast<ClassType>(*t).Name());
     case Value::Kind::ChoiceType:
-      return global_arena->New<IdentifierExpression>(
-          loc, cast<ChoiceType>(*t).Name());
+      return arena->New<IdentifierExpression>(loc, cast<ChoiceType>(*t).Name());
     case Value::Kind::PointerType:
-      return global_arena->New<PrimitiveOperatorExpression>(
+      return arena->New<PrimitiveOperatorExpression>(
           loc, Operator::Ptr,
           std::vector<Ptr<const Expression>>(
               {ReifyType(cast<PointerType>(*t).Type(), loc)}));
     case Value::Kind::VariableType:
-      return global_arena->New<IdentifierExpression>(
-          loc, cast<VariableType>(*t).Name());
+      return arena->New<IdentifierExpression>(loc,
+                                              cast<VariableType>(*t).Name());
     case Value::Kind::StringType:
-      return global_arena->New<StringTypeLiteral>(loc);
+      return arena->New<StringTypeLiteral>(loc);
     case Value::Kind::AlternativeConstructorValue:
     case Value::Kind::AlternativeValue:
     case Value::Kind::AutoType:
@@ -195,7 +192,7 @@ static auto ArgumentDeduction(SourceLocation loc, TypeEnv deduced,
   }
 }
 
-static auto Substitute(TypeEnv dict, Ptr<const Value> type)
+auto TypeChecker::Substitute(TypeEnv dict, Ptr<const Value> type)
     -> Ptr<const Value> {
   switch (type->Tag()) {
     case Value::Kind::VariableType: {
@@ -213,17 +210,17 @@ static auto Substitute(TypeEnv dict, Ptr<const Value> type)
         auto t = Substitute(dict, elt.value);
         elts.push_back({.name = elt.name, .value = t});
       }
-      return global_arena->New<TupleValue>(elts);
+      return arena->New<TupleValue>(elts);
     }
     case Value::Kind::FunctionType: {
       const auto& fn_type = cast<FunctionType>(*type);
       auto param = Substitute(dict, fn_type.Param());
       auto ret = Substitute(dict, fn_type.Ret());
-      return global_arena->New<FunctionType>(std::vector<GenericBinding>(),
-                                             param, ret);
+      return arena->New<FunctionType>(std::vector<GenericBinding>(), param,
+                                      ret);
     }
     case Value::Kind::PointerType: {
-      return global_arena->New<PointerType>(
+      return arena->New<PointerType>(
           Substitute(dict, cast<PointerType>(*type).Type()));
     }
     case Value::Kind::AutoType:
@@ -276,9 +273,9 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
             FATAL_COMPILATION_ERROR(e->SourceLoc())
                 << "field " << f << " is not in the tuple " << *t;
           }
-          auto new_e = global_arena->New<IndexExpression>(
+          auto new_e = arena->New<IndexExpression>(
               e->SourceLoc(), res.exp,
-              global_arena->New<IntLiteral>(e->SourceLoc(), i));
+              arena->New<IntLiteral>(e->SourceLoc(), i));
           return TCExpression(new_e, *field_t, res.types);
         }
         default:
@@ -295,8 +292,8 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
         new_args.push_back(FieldInitializer(arg.name, arg_res.exp));
         arg_types.push_back({.name = arg.name, .value = arg_res.type});
       }
-      auto tuple_e = global_arena->New<TupleLiteral>(e->SourceLoc(), new_args);
-      auto tuple_t = global_arena->New<TupleValue>(std::move(arg_types));
+      auto tuple_e = arena->New<TupleLiteral>(e->SourceLoc(), new_args);
+      auto tuple_t = arena->New<TupleValue>(std::move(arg_types));
       return TCExpression(tuple_e, tuple_t, new_types);
     }
     case Expression::Kind::FieldAccessExpression: {
@@ -309,18 +306,16 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
           // Search for a field
           for (auto& field : t_class.Fields()) {
             if (access.Field() == field.first) {
-              Ptr<const Expression> new_e =
-                  global_arena->New<FieldAccessExpression>(
-                      e->SourceLoc(), res.exp, access.Field());
+              Ptr<const Expression> new_e = arena->New<FieldAccessExpression>(
+                  e->SourceLoc(), res.exp, access.Field());
               return TCExpression(new_e, field.second, res.types);
             }
           }
           // Search for a method
           for (auto& method : t_class.Methods()) {
             if (access.Field() == method.first) {
-              Ptr<const Expression> new_e =
-                  global_arena->New<FieldAccessExpression>(
-                      e->SourceLoc(), res.exp, access.Field());
+              Ptr<const Expression> new_e = arena->New<FieldAccessExpression>(
+                  e->SourceLoc(), res.exp, access.Field());
               return TCExpression(new_e, method.second, res.types);
             }
           }
@@ -332,7 +327,7 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
           const auto& tup = cast<TupleValue>(*t);
           for (const TupleElement& field : tup.Elements()) {
             if (access.Field() == field.name) {
-              auto new_e = global_arena->New<FieldAccessExpression>(
+              auto new_e = arena->New<FieldAccessExpression>(
                   e->SourceLoc(), res.exp, access.Field());
               return TCExpression(new_e, field.value, res.types);
             }
@@ -345,10 +340,9 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
           const auto& choice = cast<ChoiceType>(*t);
           for (const auto& vt : choice.Alternatives()) {
             if (access.Field() == vt.first) {
-              Ptr<const Expression> new_e =
-                  global_arena->New<FieldAccessExpression>(
-                      e->SourceLoc(), res.exp, access.Field());
-              auto fun_ty = global_arena->New<FunctionType>(
+              Ptr<const Expression> new_e = arena->New<FieldAccessExpression>(
+                  e->SourceLoc(), res.exp, access.Field());
+              auto fun_ty = arena->New<FunctionType>(
                   std::vector<GenericBinding>(), vt.second, t);
               return TCExpression(new_e, fun_ty, res.types);
             }
@@ -374,9 +368,9 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
       }
     }
     case Expression::Kind::IntLiteral:
-      return TCExpression(e, global_arena->New<IntType>(), types);
+      return TCExpression(e, arena->New<IntType>(), types);
     case Expression::Kind::BoolLiteral:
-      return TCExpression(e, global_arena->New<BoolType>(), types);
+      return TCExpression(e, arena->New<BoolType>(), types);
     case Expression::Kind::PrimitiveOperatorExpression: {
       const auto& op = cast<PrimitiveOperatorExpression>(*e);
       std::vector<Ptr<const Expression>> es;
@@ -388,56 +382,51 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
         es.push_back(res.exp);
         ts.push_back(res.type);
       }
-      auto new_e = global_arena->New<PrimitiveOperatorExpression>(
-          e->SourceLoc(), op.Op(), es);
+      auto new_e =
+          arena->New<PrimitiveOperatorExpression>(e->SourceLoc(), op.Op(), es);
       switch (op.Op()) {
         case Operator::Neg:
-          ExpectType(e->SourceLoc(), "negation", global_arena->New<IntType>(),
-                     ts[0]);
-          return TCExpression(new_e, global_arena->New<IntType>(), new_types);
+          ExpectType(e->SourceLoc(), "negation", arena->New<IntType>(), ts[0]);
+          return TCExpression(new_e, arena->New<IntType>(), new_types);
         case Operator::Add:
-          ExpectType(e->SourceLoc(), "addition(1)",
-                     global_arena->New<IntType>(), ts[0]);
-          ExpectType(e->SourceLoc(), "addition(2)",
-                     global_arena->New<IntType>(), ts[1]);
-          return TCExpression(new_e, global_arena->New<IntType>(), new_types);
+          ExpectType(e->SourceLoc(), "addition(1)", arena->New<IntType>(),
+                     ts[0]);
+          ExpectType(e->SourceLoc(), "addition(2)", arena->New<IntType>(),
+                     ts[1]);
+          return TCExpression(new_e, arena->New<IntType>(), new_types);
         case Operator::Sub:
-          ExpectType(e->SourceLoc(), "subtraction(1)",
-                     global_arena->New<IntType>(), ts[0]);
-          ExpectType(e->SourceLoc(), "subtraction(2)",
-                     global_arena->New<IntType>(), ts[1]);
-          return TCExpression(new_e, global_arena->New<IntType>(), new_types);
-        case Operator::Mul:
-          ExpectType(e->SourceLoc(), "multiplication(1)",
-                     global_arena->New<IntType>(), ts[0]);
-          ExpectType(e->SourceLoc(), "multiplication(2)",
-                     global_arena->New<IntType>(), ts[1]);
-          return TCExpression(new_e, global_arena->New<IntType>(), new_types);
-        case Operator::And:
-          ExpectType(e->SourceLoc(), "&&(1)", global_arena->New<BoolType>(),
+          ExpectType(e->SourceLoc(), "subtraction(1)", arena->New<IntType>(),
                      ts[0]);
-          ExpectType(e->SourceLoc(), "&&(2)", global_arena->New<BoolType>(),
+          ExpectType(e->SourceLoc(), "subtraction(2)", arena->New<IntType>(),
                      ts[1]);
-          return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
-        case Operator::Or:
-          ExpectType(e->SourceLoc(), "||(1)", global_arena->New<BoolType>(),
+          return TCExpression(new_e, arena->New<IntType>(), new_types);
+        case Operator::Mul:
+          ExpectType(e->SourceLoc(), "multiplication(1)", arena->New<IntType>(),
                      ts[0]);
-          ExpectType(e->SourceLoc(), "||(2)", global_arena->New<BoolType>(),
+          ExpectType(e->SourceLoc(), "multiplication(2)", arena->New<IntType>(),
                      ts[1]);
-          return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
+          return TCExpression(new_e, arena->New<IntType>(), new_types);
+        case Operator::And:
+          ExpectType(e->SourceLoc(), "&&(1)", arena->New<BoolType>(), ts[0]);
+          ExpectType(e->SourceLoc(), "&&(2)", arena->New<BoolType>(), ts[1]);
+          return TCExpression(new_e, arena->New<BoolType>(), new_types);
+        case Operator::Or:
+          ExpectType(e->SourceLoc(), "||(1)", arena->New<BoolType>(), ts[0]);
+          ExpectType(e->SourceLoc(), "||(2)", arena->New<BoolType>(), ts[1]);
+          return TCExpression(new_e, arena->New<BoolType>(), new_types);
         case Operator::Not:
-          ExpectType(e->SourceLoc(), "!", global_arena->New<BoolType>(), ts[0]);
-          return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
+          ExpectType(e->SourceLoc(), "!", arena->New<BoolType>(), ts[0]);
+          return TCExpression(new_e, arena->New<BoolType>(), new_types);
         case Operator::Eq:
           ExpectType(e->SourceLoc(), "==", ts[0], ts[1]);
-          return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
+          return TCExpression(new_e, arena->New<BoolType>(), new_types);
         case Operator::Deref:
           ExpectPointerType(e->SourceLoc(), "*", ts[0]);
           return TCExpression(new_e, cast<PointerType>(*ts[0]).Type(),
                               new_types);
         case Operator::Ptr:
-          ExpectType(e->SourceLoc(), "*", global_arena->New<TypeType>(), ts[0]);
-          return TCExpression(new_e, global_arena->New<TypeType>(), new_types);
+          ExpectType(e->SourceLoc(), "*", arena->New<TypeType>(), ts[0]);
+          return TCExpression(new_e, arena->New<TypeType>(), new_types);
       }
       break;
     }
@@ -451,8 +440,8 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
           auto parameter_type = fun_t.Param();
           auto return_type = fun_t.Ret();
           if (!fun_t.Deduced().empty()) {
-            auto deduced_args = ArgumentDeduction(e->SourceLoc(), TypeEnv(),
-                                                  parameter_type, arg_res.type);
+            auto deduced_args = ArgumentDeduction(
+                e->SourceLoc(), TypeEnv(arena), parameter_type, arg_res.type);
             for (auto& deduced_param : fun_t.Deduced()) {
               // TODO: change the following to a CHECK once the real checking
               // has been added to the type checking of function signatures.
@@ -467,8 +456,8 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
           } else {
             ExpectType(e->SourceLoc(), "call", parameter_type, arg_res.type);
           }
-          auto new_e = global_arena->New<CallExpression>(
-              e->SourceLoc(), fun_res.exp, arg_res.exp);
+          auto new_e = arena->New<CallExpression>(e->SourceLoc(), fun_res.exp,
+                                                  arg_res.exp);
           return TCExpression(new_e, return_type, arg_res.types);
         }
         default: {
@@ -483,14 +472,14 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
       const auto& fn = cast<FunctionTypeLiteral>(*e);
       auto pt = interpreter.InterpExp(values, fn.Parameter());
       auto rt = interpreter.InterpExp(values, fn.ReturnType());
-      auto new_e = global_arena->New<FunctionTypeLiteral>(
+      auto new_e = arena->New<FunctionTypeLiteral>(
           e->SourceLoc(), ReifyType(pt, e->SourceLoc()),
           ReifyType(rt, e->SourceLoc()),
           /*is_omitted_return_type=*/false);
-      return TCExpression(new_e, global_arena->New<TypeType>(), types);
+      return TCExpression(new_e, arena->New<TypeType>(), types);
     }
     case Expression::Kind::StringLiteral:
-      return TCExpression(e, global_arena->New<StringType>(), types);
+      return TCExpression(e, arena->New<StringType>(), types);
     case Expression::Kind::IntrinsicExpression:
       switch (cast<IntrinsicExpression>(*e).Intrinsic()) {
         case IntrinsicExpression::IntrinsicKind::Print:
@@ -501,7 +490,7 @@ auto TypeChecker::TypeCheckExp(Ptr<const Expression> e, TypeEnv types,
     case Expression::Kind::StringTypeLiteral:
     case Expression::Kind::TypeTypeLiteral:
     case Expression::Kind::ContinuationTypeLiteral:
-      return TCExpression(e, global_arena->New<TypeType>(), types);
+      return TCExpression(e, arena->New<TypeType>(), types);
   }
 }
 
@@ -522,8 +511,7 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
   }
   switch (p->Tag()) {
     case Pattern::Kind::AutoPattern: {
-      return {
-          .pattern = p, .type = global_arena->New<TypeType>(), .types = types};
+      return {.pattern = p, .type = arena->New<TypeType>(), .types = types};
     }
     case Pattern::Kind::BindingPattern: {
       const auto& binding = cast<BindingPattern>(*p);
@@ -543,10 +531,9 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
             << "Name bindings within type patterns are unsupported";
         type = *expected;
       }
-      auto new_p = global_arena->New<BindingPattern>(
+      auto new_p = arena->New<BindingPattern>(
           binding.SourceLoc(), binding.Name(),
-          global_arena->New<ExpressionPattern>(
-              ReifyType(type, binding.SourceLoc())));
+          arena->New<ExpressionPattern>(ReifyType(type, binding.SourceLoc())));
       if (binding.Name().has_value()) {
         types.Set(*binding.Name(), type);
       }
@@ -585,9 +572,8 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
             TuplePattern::Field(field.name, field_result.pattern));
         field_types.push_back({.name = field.name, .value = field_result.type});
       }
-      auto new_tuple =
-          global_arena->New<TuplePattern>(tuple.SourceLoc(), new_fields);
-      auto tuple_t = global_arena->New<TupleValue>(std::move(field_types));
+      auto new_tuple = arena->New<TuplePattern>(tuple.SourceLoc(), new_fields);
+      auto tuple_t = arena->New<TupleValue>(std::move(field_types));
       return {.pattern = new_tuple, .type = tuple_t, .types = new_types};
     }
     case Pattern::Kind::AlternativePattern: {
@@ -616,7 +602,7 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
       // (multiple TODOs)
       auto arguments = Ptr<const TuplePattern>(
           cast<const TuplePattern>(arg_results.pattern.Get()));
-      return {.pattern = global_arena->New<AlternativePattern>(
+      return {.pattern = arena->New<AlternativePattern>(
                   alternative.SourceLoc(),
                   ReifyType(choice_type, alternative.SourceLoc()),
                   alternative.AlternativeName(), arguments),
@@ -626,7 +612,7 @@ auto TypeChecker::TypeCheckPattern(Ptr<const Pattern> p, TypeEnv types,
     case Pattern::Kind::ExpressionPattern: {
       TCExpression result =
           TypeCheckExp(cast<ExpressionPattern>(*p).Expression(), types, values);
-      return {.pattern = global_arena->New<ExpressionPattern>(result.exp),
+      return {.pattern = arena->New<ExpressionPattern>(result.exp),
               .type = result.type,
               .types = result.types};
     }
@@ -660,19 +646,18 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
                                             clause.second, types, values,
                                             ret_type, is_omitted_ret_type));
       }
-      auto new_s =
-          global_arena->New<Match>(s->SourceLoc(), res.exp, new_clauses);
+      auto new_s = arena->New<Match>(s->SourceLoc(), res.exp, new_clauses);
       return TCStatement(new_s, types);
     }
     case Statement::Kind::While: {
       const auto& while_stmt = cast<While>(*s);
       auto cnd_res = TypeCheckExp(while_stmt.Cond(), types, values);
-      ExpectType(s->SourceLoc(), "condition of `while`",
-                 global_arena->New<BoolType>(), cnd_res.type);
+      ExpectType(s->SourceLoc(), "condition of `while`", arena->New<BoolType>(),
+                 cnd_res.type);
       auto body_res = TypeCheckStmt(while_stmt.Body(), types, values, ret_type,
                                     is_omitted_ret_type);
       auto new_s =
-          global_arena->New<While>(s->SourceLoc(), cnd_res.exp, body_res.stmt);
+          arena->New<While>(s->SourceLoc(), cnd_res.exp, body_res.stmt);
       return TCStatement(new_s, types);
     }
     case Statement::Kind::Break:
@@ -683,8 +668,8 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
       if (block.Stmt()) {
         auto stmt_res = TypeCheckStmt(*block.Stmt(), types, values, ret_type,
                                       is_omitted_ret_type);
-        return TCStatement(
-            global_arena->New<Block>(s->SourceLoc(), stmt_res.stmt), types);
+        return TCStatement(arena->New<Block>(s->SourceLoc(), stmt_res.stmt),
+                           types);
       } else {
         return TCStatement(s, types);
       }
@@ -694,8 +679,8 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
       auto res = TypeCheckExp(var.Init(), types, values);
       Ptr<const Value> rhs_ty = res.type;
       auto lhs_res = TypeCheckPattern(var.Pat(), types, values, rhs_ty);
-      auto new_s = global_arena->New<VariableDefinition>(s->SourceLoc(),
-                                                         var.Pat(), res.exp);
+      auto new_s =
+          arena->New<VariableDefinition>(s->SourceLoc(), var.Pat(), res.exp);
       return TCStatement(new_s, lhs_res.types);
     }
     case Statement::Kind::Sequence: {
@@ -711,7 +696,7 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
         checked_types = next_res.types;
       }
       return TCStatement(
-          global_arena->New<Sequence>(s->SourceLoc(), stmt_res.stmt, next_stmt),
+          arena->New<Sequence>(s->SourceLoc(), stmt_res.stmt, next_stmt),
           checked_types);
     }
     case Statement::Kind::Assign: {
@@ -721,22 +706,20 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
       auto lhs_res = TypeCheckExp(assign.Lhs(), types, values);
       auto lhs_t = lhs_res.type;
       ExpectType(s->SourceLoc(), "assign", lhs_t, rhs_t);
-      auto new_s =
-          global_arena->New<Assign>(s->SourceLoc(), lhs_res.exp, rhs_res.exp);
+      auto new_s = arena->New<Assign>(s->SourceLoc(), lhs_res.exp, rhs_res.exp);
       return TCStatement(new_s, lhs_res.types);
     }
     case Statement::Kind::ExpressionStatement: {
       auto res =
           TypeCheckExp(cast<ExpressionStatement>(*s).Exp(), types, values);
-      auto new_s =
-          global_arena->New<ExpressionStatement>(s->SourceLoc(), res.exp);
+      auto new_s = arena->New<ExpressionStatement>(s->SourceLoc(), res.exp);
       return TCStatement(new_s, types);
     }
     case Statement::Kind::If: {
       const auto& if_stmt = cast<If>(*s);
       auto cnd_res = TypeCheckExp(if_stmt.Cond(), types, values);
-      ExpectType(s->SourceLoc(), "condition of `if`",
-                 global_arena->New<BoolType>(), cnd_res.type);
+      ExpectType(s->SourceLoc(), "condition of `if`", arena->New<BoolType>(),
+                 cnd_res.type);
       auto then_res = TypeCheckStmt(if_stmt.ThenStmt(), types, values, ret_type,
                                     is_omitted_ret_type);
       std::optional<Ptr<const Statement>> else_stmt;
@@ -745,8 +728,8 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
                                       ret_type, is_omitted_ret_type);
         else_stmt = else_res.stmt;
       }
-      auto new_s = global_arena->New<If>(s->SourceLoc(), cnd_res.exp,
-                                         then_res.stmt, else_stmt);
+      auto new_s =
+          arena->New<If>(s->SourceLoc(), cnd_res.exp, then_res.stmt, else_stmt);
       return TCStatement(new_s, types);
     }
     case Statement::Kind::Return: {
@@ -765,27 +748,25 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
             << *s << " should" << (is_omitted_ret_type ? " not" : "")
             << " provide a return value, to match the function's signature.";
       }
-      return TCStatement(global_arena->New<Return>(s->SourceLoc(), res.exp,
-                                                   ret.IsOmittedExp()),
-                         types);
+      return TCStatement(
+          arena->New<Return>(s->SourceLoc(), res.exp, ret.IsOmittedExp()),
+          types);
     }
     case Statement::Kind::Continuation: {
       const auto& cont = cast<Continuation>(*s);
       TCStatement body_result = TypeCheckStmt(cont.Body(), types, values,
                                               ret_type, is_omitted_ret_type);
-      auto new_continuation = global_arena->New<Continuation>(
+      auto new_continuation = arena->New<Continuation>(
           s->SourceLoc(), cont.ContinuationVariable(), body_result.stmt);
-      types.Set(cont.ContinuationVariable(),
-                global_arena->New<ContinuationType>());
+      types.Set(cont.ContinuationVariable(), arena->New<ContinuationType>());
       return TCStatement(new_continuation, types);
     }
     case Statement::Kind::Run: {
       TCExpression argument_result =
           TypeCheckExp(cast<Run>(*s).Argument(), types, values);
       ExpectType(s->SourceLoc(), "argument of `run`",
-                 global_arena->New<ContinuationType>(), argument_result.type);
-      auto new_run =
-          global_arena->New<Run>(s->SourceLoc(), argument_result.exp);
+                 arena->New<ContinuationType>(), argument_result.type);
+      auto new_run = arena->New<Run>(s->SourceLoc(), argument_result.exp);
       return TCStatement(new_run, types);
     }
     case Statement::Kind::Await: {
@@ -795,12 +776,12 @@ auto TypeChecker::TypeCheckStmt(Ptr<const Statement> s, TypeEnv types,
   }  // switch
 }
 
-static auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
-                                bool omitted_ret_type, SourceLocation loc)
-    -> Ptr<const Statement> {
+auto TypeChecker::CheckOrEnsureReturn(
+    std::optional<Ptr<const Statement>> opt_stmt, bool omitted_ret_type,
+    SourceLocation loc) -> Ptr<const Statement> {
   if (!opt_stmt) {
     if (omitted_ret_type) {
-      return global_arena->New<Return>(loc);
+      return arena->New<Return>(arena, loc);
     } else {
       FATAL_COMPILATION_ERROR(loc)
           << "control-flow reaches end of function that provides a `->` return "
@@ -818,17 +799,16 @@ static auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
                                      stmt->SourceLoc());
         new_clauses.push_back(std::make_pair(clause.first, s));
       }
-      return global_arena->New<Match>(stmt->SourceLoc(), match.Exp(),
-                                      new_clauses);
+      return arena->New<Match>(stmt->SourceLoc(), match.Exp(), new_clauses);
     }
     case Statement::Kind::Block:
-      return global_arena->New<Block>(
+      return arena->New<Block>(
           stmt->SourceLoc(),
           CheckOrEnsureReturn(cast<Block>(*stmt).Stmt(), omitted_ret_type,
                               stmt->SourceLoc()));
     case Statement::Kind::If: {
       const auto& if_stmt = cast<If>(*stmt);
-      return global_arena->New<If>(
+      return arena->New<If>(
           stmt->SourceLoc(), if_stmt.Cond(),
           CheckOrEnsureReturn(if_stmt.ThenStmt(), omitted_ret_type,
                               stmt->SourceLoc()),
@@ -840,7 +820,7 @@ static auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
     case Statement::Kind::Sequence: {
       const auto& seq = cast<Sequence>(*stmt);
       if (seq.Next()) {
-        return global_arena->New<Sequence>(
+        return arena->New<Sequence>(
             stmt->SourceLoc(), seq.Stmt(),
             CheckOrEnsureReturn(seq.Next(), omitted_ret_type,
                                 stmt->SourceLoc()));
@@ -860,8 +840,8 @@ static auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
     case Statement::Kind::Continue:
     case Statement::Kind::VariableDefinition:
       if (omitted_ret_type) {
-        return global_arena->New<Sequence>(stmt->SourceLoc(), stmt,
-                                           global_arena->New<Return>(loc));
+        return arena->New<Sequence>(stmt->SourceLoc(), stmt,
+                                    arena->New<Return>(arena, loc));
       } else {
         FATAL_COMPILATION_ERROR(stmt->SourceLoc())
             << "control-flow reaches end of function that provides a `->` "
@@ -879,7 +859,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
   // Bring the deduced parameters into scope
   for (const auto& deduced : f->deduced_parameters) {
     // auto t = interpreter.InterpExp(values, deduced.type);
-    types.Set(deduced.name, global_arena->New<VariableType>(deduced.name));
+    types.Set(deduced.name, arena->New<VariableType>(deduced.name));
     Address a = interpreter.AllocateValue(*types.Get(deduced.name));
     values.Set(deduced.name, a);
   }
@@ -890,7 +870,7 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
   auto return_type = interpreter.InterpPattern(values, f->return_type);
   if (f->name == "main") {
     ExpectType(f->source_location, "return type of `main`",
-               global_arena->New<IntType>(), return_type);
+               arena->New<IntType>(), return_type);
     // TODO: Check that main doesn't have any parameters.
   }
   std::optional<Ptr<const Statement>> body_stmt;
@@ -901,10 +881,9 @@ auto TypeChecker::TypeCheckFunDef(const FunctionDefinition* f, TypeEnv types,
   }
   auto body = CheckOrEnsureReturn(body_stmt, f->is_omitted_return_type,
                                   f->source_location);
-  return global_arena->New<FunctionDefinition>(
+  return arena->New<FunctionDefinition>(
       f->source_location, f->name, f->deduced_parameters, f->param_pattern,
-      global_arena->New<ExpressionPattern>(
-          ReifyType(return_type, f->source_location)),
+      arena->New<ExpressionPattern>(ReifyType(return_type, f->source_location)),
       /*is_omitted_return_type=*/false, body);
 }
 
@@ -914,7 +893,7 @@ auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values,
   // Bring the deduced parameters into scope
   for (const auto& deduced : fun_def->deduced_parameters) {
     // auto t = interpreter.InterpExp(values, deduced.type);
-    types.Set(deduced.name, global_arena->New<VariableType>(deduced.name));
+    types.Set(deduced.name, arena->New<VariableType>(deduced.name));
     Address a = interpreter.AllocateValue(*types.Get(deduced.name));
     values.Set(deduced.name, a);
   }
@@ -927,8 +906,8 @@ auto TypeChecker::TypeOfFunDef(TypeEnv types, Env values,
     auto f = TypeCheckFunDef(fun_def, types, values);
     ret = interpreter.InterpPattern(values, f->return_type);
   }
-  return global_arena->New<FunctionType>(fun_def->deduced_parameters,
-                                         param_res.type, ret);
+  return arena->New<FunctionType>(fun_def->deduced_parameters, param_res.type,
+                                  ret);
 }
 
 auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/,
@@ -955,8 +934,7 @@ auto TypeChecker::TypeOfClassDef(const ClassDefinition* sd, TypeEnv /*types*/,
       }
     }
   }
-  return global_arena->New<ClassType>(sd->name, std::move(fields),
-                                      std::move(methods));
+  return arena->New<ClassType>(sd->name, std::move(fields), std::move(methods));
 }
 
 static auto GetName(const Declaration& d) -> const std::string& {
@@ -984,7 +962,7 @@ auto TypeChecker::MakeTypeChecked(const Ptr<const Declaration> d,
     -> Ptr<const Declaration> {
   switch (d->Tag()) {
     case Declaration::Kind::FunctionDeclaration:
-      return global_arena->New<FunctionDeclaration>(TypeCheckFunDef(
+      return arena->New<FunctionDeclaration>(TypeCheckFunDef(
           &cast<FunctionDeclaration>(*d).Definition(), types, values));
 
     case Declaration::Kind::ClassDeclaration: {
@@ -999,8 +977,8 @@ auto TypeChecker::MakeTypeChecked(const Ptr<const Declaration> d,
             break;
         }
       }
-      return global_arena->New<ClassDeclaration>(class_def.loc, class_def.name,
-                                                 std::move(fields));
+      return arena->New<ClassDeclaration>(class_def.loc, class_def.name,
+                                          std::move(fields));
     }
 
     case Declaration::Kind::ChoiceDeclaration:
@@ -1051,9 +1029,9 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
            cast<ClassType>(*st).Fields()) {
         field_types.push_back({.name = field_name, .value = field_value});
       }
-      auto fun_ty = global_arena->New<FunctionType>(
+      auto fun_ty = arena->New<FunctionType>(
           std::vector<GenericBinding>(),
-          global_arena->New<TupleValue>(std::move(field_types)), st);
+          arena->New<TupleValue>(std::move(field_types)), st);
       tops->types.Set(class_def.name, fun_ty);
       break;
     }
@@ -1065,7 +1043,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
         auto t = interpreter.InterpExp(tops->values, signature);
         alts.push_back(std::make_pair(name, t));
       }
-      auto ct = global_arena->New<ChoiceType>(choice.Name(), std::move(alts));
+      auto ct = arena->New<ChoiceType>(choice.Name(), std::move(alts));
       Address a = interpreter.AllocateValue(ct);
       tops->values.Set(choice.Name(), a);  // Is this obsolete?
       tops->types.Set(choice.Name(), ct);
@@ -1088,7 +1066,7 @@ void TypeChecker::TopLevel(const Declaration& d, TypeCheckContext* tops) {
 
 auto TypeChecker::TopLevel(const std::vector<Ptr<const Declaration>>& fs)
     -> TypeCheckContext {
-  TypeCheckContext tops;
+  TypeCheckContext tops(arena);
   bool found_main = false;
 
   for (auto const& d : fs) {

+ 15 - 0
executable_semantics/interpreter/type_checker.h

@@ -20,7 +20,11 @@ using TypeEnv = Dictionary<std::string, Ptr<const Value>>;
 
 class TypeChecker {
  public:
+  explicit TypeChecker(Ptr<Arena> arena) : arena(arena), interpreter(arena) {}
+
   struct TypeCheckContext {
+    TypeCheckContext(Ptr<Arena> arena) : types(arena), values(arena) {}
+
     // Symbol table mapping names of runtime entities to their type.
     TypeEnv types;
     // Symbol table mapping names of compile time entities to their value.
@@ -104,6 +108,17 @@ class TypeChecker {
 
   void TopLevel(const Declaration& d, TypeCheckContext* tops);
 
+  auto CheckOrEnsureReturn(std::optional<Ptr<const Statement>> opt_stmt,
+                           bool omitted_ret_type, SourceLocation loc)
+      -> Ptr<const Statement>;
+
+  // Reify type to type expression.
+  auto ReifyType(Ptr<const Value> t, SourceLocation loc)
+      -> Ptr<const Expression>;
+
+  auto Substitute(TypeEnv dict, Ptr<const Value> type) -> Ptr<const Value>;
+
+  Ptr<Arena> arena;
   Interpreter interpreter;
 };
 

+ 41 - 40
executable_semantics/interpreter/value.cpp

@@ -56,8 +56,8 @@ auto TupleValue::FindField(const std::string& name) const
 
 namespace {
 
-auto GetMember(Ptr<const Value> v, const std::string& f, SourceLocation loc)
-    -> Ptr<const Value> {
+auto GetMember(Ptr<Arena> arena, Ptr<const Value> v, const std::string& f,
+               SourceLocation loc) -> Ptr<const Value> {
   switch (v->Tag()) {
     case Value::Kind::StructValue: {
       std::optional<Ptr<const Value>> field =
@@ -79,7 +79,7 @@ auto GetMember(Ptr<const Value> v, const std::string& f, SourceLocation loc)
       if (!FindInVarValues(f, choice.Alternatives())) {
         FATAL_RUNTIME_ERROR(loc) << "alternative " << f << " not in " << *v;
       }
-      return global_arena->New<AlternativeConstructorValue>(f, choice.Name());
+      return arena->New<AlternativeConstructorValue>(f, choice.Name());
     }
     default:
       FATAL() << "field access not allowed for value " << *v;
@@ -88,18 +88,18 @@ auto GetMember(Ptr<const Value> v, const std::string& f, SourceLocation loc)
 
 }  // namespace
 
-auto Value::GetField(const FieldPath& path, SourceLocation loc) const
-    -> Ptr<const Value> {
+auto Value::GetField(Ptr<Arena> arena, const FieldPath& path,
+                     SourceLocation loc) const -> Ptr<const Value> {
   Ptr<const Value> value(this);
   for (const std::string& field : path.components) {
-    value = GetMember(value, field, loc);
+    value = GetMember(arena, value, field, loc);
   }
   return value;
 }
 
 namespace {
 
-auto SetFieldImpl(Ptr<const Value> value,
+auto SetFieldImpl(Ptr<Arena> arena, Ptr<const Value> value,
                   std::vector<std::string>::const_iterator path_begin,
                   std::vector<std::string>::const_iterator path_end,
                   Ptr<const Value> field_value, SourceLocation loc)
@@ -109,7 +109,7 @@ auto SetFieldImpl(Ptr<const Value> value,
   }
   switch (value->Tag()) {
     case Value::Kind::StructValue: {
-      return SetFieldImpl(cast<StructValue>(*value).Inits(), path_begin,
+      return SetFieldImpl(arena, cast<StructValue>(*value).Inits(), path_begin,
                           path_end, field_value, loc);
     }
     case Value::Kind::TupleValue: {
@@ -122,9 +122,9 @@ auto SetFieldImpl(Ptr<const Value> value,
         FATAL_RUNTIME_ERROR(loc)
             << "field " << *path_begin << " not in " << *value;
       }
-      it->value =
-          SetFieldImpl(it->value, path_begin + 1, path_end, field_value, loc);
-      return global_arena->New<TupleValue>(elements);
+      it->value = SetFieldImpl(arena, it->value, path_begin + 1, path_end,
+                               field_value, loc);
+      return arena->New<TupleValue>(elements);
     }
     default:
       FATAL() << "field access not allowed for value " << *value;
@@ -133,9 +133,10 @@ auto SetFieldImpl(Ptr<const Value> value,
 
 }  // namespace
 
-auto Value::SetField(const FieldPath& path, Ptr<const Value> field_value,
-                     SourceLocation loc) const -> Ptr<const Value> {
-  return SetFieldImpl(Ptr<const Value>(this), path.components.begin(),
+auto Value::SetField(Ptr<Arena> arena, const FieldPath& path,
+                     Ptr<const Value> field_value, SourceLocation loc) const
+    -> Ptr<const Value> {
+  return SetFieldImpl(arena, Ptr<const Value>(this), path.components.begin(),
                       path.components.end(), field_value, loc);
 }
 
@@ -253,64 +254,64 @@ void Value::Print(llvm::raw_ostream& out) const {
   }
 }
 
-auto CopyVal(Ptr<const Value> val, SourceLocation loc) -> Ptr<const Value> {
+auto CopyVal(Ptr<Arena> arena, Ptr<const Value> val, SourceLocation loc)
+    -> Ptr<const Value> {
   switch (val->Tag()) {
     case Value::Kind::TupleValue: {
       std::vector<TupleElement> elements;
       for (const TupleElement& element : cast<TupleValue>(*val).Elements()) {
-        elements.push_back(
-            {.name = element.name, .value = CopyVal(element.value, loc)});
+        elements.push_back({.name = element.name,
+                            .value = CopyVal(arena, element.value, loc)});
       }
-      return global_arena->New<TupleValue>(std::move(elements));
+      return arena->New<TupleValue>(std::move(elements));
     }
     case Value::Kind::AlternativeValue: {
       const auto& alt = cast<AlternativeValue>(*val);
-      Ptr<const Value> arg = CopyVal(alt.Argument(), loc);
-      return global_arena->New<AlternativeValue>(alt.AltName(),
-                                                 alt.ChoiceName(), arg);
+      Ptr<const Value> arg = CopyVal(arena, alt.Argument(), loc);
+      return arena->New<AlternativeValue>(alt.AltName(), alt.ChoiceName(), arg);
     }
     case Value::Kind::StructValue: {
       const auto& s = cast<StructValue>(*val);
-      Ptr<const Value> inits = CopyVal(s.Inits(), loc);
-      return global_arena->New<StructValue>(s.Type(), inits);
+      Ptr<const Value> inits = CopyVal(arena, s.Inits(), loc);
+      return arena->New<StructValue>(s.Type(), inits);
     }
     case Value::Kind::IntValue:
-      return global_arena->New<IntValue>(cast<IntValue>(*val).Val());
+      return arena->New<IntValue>(cast<IntValue>(*val).Val());
     case Value::Kind::BoolValue:
-      return global_arena->New<BoolValue>(cast<BoolValue>(*val).Val());
+      return arena->New<BoolValue>(cast<BoolValue>(*val).Val());
     case Value::Kind::FunctionValue: {
       const auto& fn_value = cast<FunctionValue>(*val);
-      return global_arena->New<FunctionValue>(fn_value.Name(), fn_value.Param(),
-                                              fn_value.Body());
+      return arena->New<FunctionValue>(fn_value.Name(), fn_value.Param(),
+                                       fn_value.Body());
     }
     case Value::Kind::PointerValue:
-      return global_arena->New<PointerValue>(cast<PointerValue>(*val).Val());
+      return arena->New<PointerValue>(cast<PointerValue>(*val).Val());
     case Value::Kind::ContinuationValue:
       // Copying a continuation is "shallow".
       return val;
     case Value::Kind::FunctionType: {
       const auto& fn_type = cast<FunctionType>(*val);
-      return global_arena->New<FunctionType>(fn_type.Deduced(),
-                                             CopyVal(fn_type.Param(), loc),
-                                             CopyVal(fn_type.Ret(), loc));
+      return arena->New<FunctionType>(fn_type.Deduced(),
+                                      CopyVal(arena, fn_type.Param(), loc),
+                                      CopyVal(arena, fn_type.Ret(), loc));
     }
     case Value::Kind::PointerType:
-      return global_arena->New<PointerType>(
-          CopyVal(cast<PointerType>(*val).Type(), loc));
+      return arena->New<PointerType>(
+          CopyVal(arena, cast<PointerType>(*val).Type(), loc));
     case Value::Kind::IntType:
-      return global_arena->New<IntType>();
+      return arena->New<IntType>();
     case Value::Kind::BoolType:
-      return global_arena->New<BoolType>();
+      return arena->New<BoolType>();
     case Value::Kind::TypeType:
-      return global_arena->New<TypeType>();
+      return arena->New<TypeType>();
     case Value::Kind::AutoType:
-      return global_arena->New<AutoType>();
+      return arena->New<AutoType>();
     case Value::Kind::ContinuationType:
-      return global_arena->New<ContinuationType>();
+      return arena->New<ContinuationType>();
     case Value::Kind::StringType:
-      return global_arena->New<StringType>();
+      return arena->New<StringType>();
     case Value::Kind::StringValue:
-      return global_arena->New<StringValue>(cast<StringValue>(*val).Val());
+      return arena->New<StringValue>(cast<StringValue>(*val).Val());
     case Value::Kind::VariableType:
     case Value::Kind::ClassType:
     case Value::Kind::ChoiceType:

+ 7 - 5
executable_semantics/interpreter/value.h

@@ -68,13 +68,14 @@ class Value {
 
   // Returns the sub-Value specified by `path`, which must be a valid field
   // path for *this.
-  auto GetField(const FieldPath& path, SourceLocation loc) const
-      -> Ptr<const Value>;
+  auto GetField(Ptr<Arena> arena, const FieldPath& path,
+                SourceLocation loc) const -> Ptr<const Value>;
 
   // Returns a copy of *this, but with the sub-Value specified by `path`
   // set to `field_value`. `path` must be a valid field path for *this.
-  auto SetField(const FieldPath& path, Ptr<const Value> field_value,
-                SourceLocation loc) const -> Ptr<const Value>;
+  auto SetField(Ptr<Arena> arena, const FieldPath& path,
+                Ptr<const Value> field_value, SourceLocation loc) const
+      -> Ptr<const Value>;
 
  protected:
   // Constructs a Value. `tag` must be the enumerator corresponding to the
@@ -474,7 +475,8 @@ class StringValue : public Value {
   std::string val;
 };
 
-auto CopyVal(Ptr<const Value> val, SourceLocation loc) -> Ptr<const Value>;
+auto CopyVal(Ptr<Arena> arena, Ptr<const Value> val, SourceLocation loc)
+    -> Ptr<const Value>;
 
 auto TypeEqual(Ptr<const Value> t1, Ptr<const Value> t2) -> bool;
 auto ValueEqual(Ptr<const Value> v1, Ptr<const Value> v2, SourceLocation loc)

+ 3 - 2
executable_semantics/main.cpp

@@ -30,8 +30,9 @@ int main(int argc, char* argv[]) {
     Carbon::tracing_output = true;
   }
 
+  Carbon::Arena arena;
   std::variant<Carbon::AST, Carbon::SyntaxErrorCode> ast_or_error =
-      Carbon::Parse(input_file_name);
+      Carbon::Parse(PtrTo(arena), input_file_name);
 
   if (auto* error = std::get_if<Carbon::SyntaxErrorCode>(&ast_or_error)) {
     // Diagnostic already reported to std::cerr; this is just a return code.
@@ -39,5 +40,5 @@ int main(int argc, char* argv[]) {
   }
 
   // Typecheck and run the parsed program.
-  Carbon::ExecProgram(std::get<Carbon::AST>(ast_or_error));
+  Carbon::ExecProgram(PtrTo(arena), std::get<Carbon::AST>(ast_or_error));
 }

+ 6 - 9
executable_semantics/syntax/parse.cpp

@@ -13,10 +13,7 @@
 
 namespace Carbon {
 
-// Returns an abstract representation of the program contained in the
-// well-formed input file, or if the file was malformed, a description of the
-// problem.
-auto Parse(const std::string& input_file_name)
+auto Parse(Ptr<Arena> arena, const std::string& input_file_name)
     -> std::variant<AST, SyntaxErrorCode> {
   FILE* input_file = fopen(input_file_name.c_str(), "r");
   if (input_file == nullptr) {
@@ -30,11 +27,11 @@ auto Parse(const std::string& input_file_name)
   yyset_in(input_file, scanner);
 
   // Prepare other parser arguments.
-  std::optional<AST> parsed_input = std::nullopt;
-  ParseAndLexContext context(input_file_name);
+  std::optional<AST> ast = std::nullopt;
+  ParseAndLexContext context(arena->New<std::string>(input_file_name));
 
   // Do the parse.
-  auto parser = Parser(parsed_input, scanner, context);
+  auto parser = Parser(arena, scanner, context, &ast);
   if (tracing_output) {
     parser.set_debug_level(1);
   }
@@ -50,9 +47,9 @@ auto Parse(const std::string& input_file_name)
   }
 
   // Return parse results.
-  CHECK(parsed_input != std::nullopt)
+  CHECK(ast != std::nullopt)
       << "parser validated syntax yet didn't produce an AST.";
-  return *parsed_input;
+  return *ast;
 }
 
 }  // namespace Carbon

+ 3 - 2
executable_semantics/syntax/parse.h

@@ -9,6 +9,7 @@
 #include <variant>
 
 #include "executable_semantics/ast/ast.h"
+#include "executable_semantics/common/arena.h"
 
 namespace Carbon {
 
@@ -16,8 +17,8 @@ namespace Carbon {
 using SyntaxErrorCode = int;
 
 // Returns the AST representing the contents of the named file, or an error code
-// if parsing fails.
-auto Parse(const std::string& input_file_name)
+// if parsing fails. Allocations go into the provided arena.
+auto Parse(Ptr<Arena> arena, const std::string& input_file_name)
     -> std::variant<Carbon::AST, SyntaxErrorCode>;
 
 }  // namespace Carbon

+ 5 - 4
executable_semantics/syntax/parse_and_lex_context.h

@@ -17,8 +17,8 @@ namespace Carbon {
 class ParseAndLexContext {
  public:
   // Creates an instance analyzing the given input file.
-  ParseAndLexContext(const std::string& input_file)
-      : input_file_name(global_arena->New<std::string>(input_file)) {}
+  ParseAndLexContext(Ptr<const std::string> input_file_name)
+      : input_file_name(input_file_name) {}
 
   // Writes a syntax error diagnostic containing message to standard error.
   auto PrintDiagnostic(const std::string& message) -> void;
@@ -40,8 +40,9 @@ class ParseAndLexContext {
 }  // namespace Carbon
 
 // Gives flex the yylex prototype we want.
-#define YY_DECL                                         \
-  Carbon::Parser::symbol_type yylex(yyscan_t yyscanner, \
+#define YY_DECL                                                       \
+  Carbon::Parser::symbol_type yylex(Carbon::Ptr<Carbon::Arena> arena, \
+                                    yyscan_t yyscanner,               \
                                     Carbon::ParseAndLexContext& context)
 
 // Declares yylex for the parser's sake.

+ 81 - 87
executable_semantics/syntax/parser.ypp

@@ -37,13 +37,14 @@
 // Parameters to the parser are stored therein as protected data members, and
 // thus available to its methods.
 
-// "out" parameter passed to the parser, where the AST is written.
-%parse-param {std::optional<AST>& parsed_program}
-
 // "inout" parameters passed to both the parser and the lexer.
+%param {Ptr<Arena> arena}
 %param {yyscan_t yyscanner}
 %param {ParseAndLexContext& context}
 
+// "out" parameter passed to the parser, where the AST is written.
+%parse-param {std::optional<AST>* ast}
+
 // No shift-reduce conflicts are expected.
 %expect 0
 
@@ -231,10 +232,10 @@
 %%
 input: package_directive import_directives declaration_list
     {
-      parsed_program = AST({.package = $1.first,
-                            .is_api = $1.second,
-                            .imports = std::move($2),
-                            .declarations = std::move($3)});
+      *ast = AST({.package = $1.first,
+                  .is_api = $1.second,
+                  .imports = std::move($2),
+                  .declarations = std::move($3)});
     }
 ;
 package_directive:
@@ -268,127 +269,124 @@ api_or_impl:
 ;
 expression:
   identifier
-    { $$ = global_arena->New<IdentifierExpression>(context.SourceLoc(), $1); }
+    { $$ = arena->New<IdentifierExpression>(context.SourceLoc(), $1); }
 | expression designator
-    {
-      $$ =
-          global_arena->New<FieldAccessExpression>(context.SourceLoc(), $1, $2);
-    }
+    { $$ = arena->New<FieldAccessExpression>(context.SourceLoc(), $1, $2); }
 | expression LEFT_SQUARE_BRACKET expression RIGHT_SQUARE_BRACKET
-    { $$ = global_arena->New<IndexExpression>(context.SourceLoc(), $1, $3); }
+    { $$ = arena->New<IndexExpression>(context.SourceLoc(), $1, $3); }
 | integer_literal
-    { $$ = global_arena->New<IntLiteral>(context.SourceLoc(), $1); }
+    { $$ = arena->New<IntLiteral>(context.SourceLoc(), $1); }
 | string_literal
-    { $$ = global_arena->New<StringLiteral>(context.SourceLoc(), $1); }
+    { $$ = arena->New<StringLiteral>(context.SourceLoc(), $1); }
 | TRUE
-    { $$ = global_arena->New<BoolLiteral>(context.SourceLoc(), true); }
+    { $$ = arena->New<BoolLiteral>(context.SourceLoc(), true); }
 | FALSE
-    { $$ = global_arena->New<BoolLiteral>(context.SourceLoc(), false); }
+    { $$ = arena->New<BoolLiteral>(context.SourceLoc(), false); }
 | sized_type_literal
     {
       int val;
       CHECK(llvm::to_integer(llvm::StringRef($1).substr(1), val));
       CHECK($1[0] == 'i' && val == 32)
           << "Only i32 is supported for now: " << $1;
-      $$ = global_arena->New<IntTypeLiteral>(context.SourceLoc());
+      $$ = arena->New<IntTypeLiteral>(context.SourceLoc());
     }
 | STRING
-    { $$ = global_arena->New<StringTypeLiteral>(context.SourceLoc()); }
+    { $$ = arena->New<StringTypeLiteral>(context.SourceLoc()); }
 | BOOL
-    { $$ = global_arena->New<BoolTypeLiteral>(context.SourceLoc()); }
+    { $$ = arena->New<BoolTypeLiteral>(context.SourceLoc()); }
 | TYPE
-    { $$ = global_arena->New<TypeTypeLiteral>(context.SourceLoc()); }
+    { $$ = arena->New<TypeTypeLiteral>(context.SourceLoc()); }
 | CONTINUATION_TYPE
-    { $$ = global_arena->New<ContinuationTypeLiteral>(context.SourceLoc()); }
+    { $$ = arena->New<ContinuationTypeLiteral>(context.SourceLoc()); }
 | paren_expression { $$ = $1; }
 | expression EQUAL_EQUAL expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Eq,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | expression PLUS expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Add,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | expression MINUS expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Sub,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | expression BINARY_STAR expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Mul,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | expression AND expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::And,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | expression OR expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Or,
           std::vector<Ptr<const Expression>>({$1, $3}));
     }
 | NOT expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Not,
           std::vector<Ptr<const Expression>>({$2}));
     }
 | MINUS expression %prec UNARY_MINUS
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Neg,
           std::vector<Ptr<const Expression>>({$2}));
     }
 | PREFIX_STAR expression
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Deref,
           std::vector<Ptr<const Expression>>({$2}));
     }
 | UNARY_STAR expression %prec PREFIX_STAR
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Deref,
           std::vector<Ptr<const Expression>>({$2}));
     }
 | expression tuple
-    { $$ = global_arena->New<CallExpression>(context.SourceLoc(), $1, $2); }
+    { $$ = arena->New<CallExpression>(context.SourceLoc(), $1, $2); }
 | expression POSTFIX_STAR
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Ptr,
           std::vector<Ptr<const Expression>>({$1}));
     }
 | expression UNARY_STAR
     {
-      $$ = global_arena->New<PrimitiveOperatorExpression>(
+      $$ = arena->New<PrimitiveOperatorExpression>(
           context.SourceLoc(), Operator::Ptr,
           std::vector<Ptr<const Expression>>({$1}));
     }
 | FNTY tuple return_type
     {
       auto [return_exp, is_omitted_exp] = $3.Release();
-      $$ = global_arena->New<FunctionTypeLiteral>(context.SourceLoc(), $2,
-                                                  return_exp, is_omitted_exp);
+      $$ = arena->New<FunctionTypeLiteral>(context.SourceLoc(), $2, return_exp,
+                                           is_omitted_exp);
     }
 ;
 designator: PERIOD identifier { $$ = $2; }
 ;
 paren_expression: paren_expression_base
-    { $$ = ExpressionFromParenContents(context.SourceLoc(), $1); }
+    { $$ = ExpressionFromParenContents(arena, context.SourceLoc(), $1); }
 ;
 tuple: paren_expression_base
-    { $$ = TupleExpressionFromParenContents(context.SourceLoc(), $1); }
+    { $$ = TupleExpressionFromParenContents(arena, context.SourceLoc(), $1); }
 ;
 paren_expression_element:
   expression
@@ -427,24 +425,24 @@ pattern:
   non_expression_pattern
     { $$ = $1; }
 | expression
-    { $$ = global_arena->New<ExpressionPattern>($1); }
+    { $$ = arena->New<ExpressionPattern>($1); }
 ;
 non_expression_pattern:
   AUTO
-    { $$ = global_arena->New<AutoPattern>(context.SourceLoc()); }
+    { $$ = arena->New<AutoPattern>(context.SourceLoc()); }
 | binding_lhs COLON pattern
-    { $$ = global_arena->New<BindingPattern>(context.SourceLoc(), $1, $3); }
+    { $$ = arena->New<BindingPattern>(context.SourceLoc(), $1, $3); }
 | paren_pattern
     { $$ = $1; }
 | expression tuple_pattern
-    { $$ = global_arena->New<AlternativePattern>(context.SourceLoc(), $1, $2); }
+    { $$ = arena->New<AlternativePattern>(context.SourceLoc(), $1, $2); }
 ;
 binding_lhs:
   identifier { $$ = $1; }
 | UNDERSCORE { $$ = std::nullopt; }
 ;
 paren_pattern: paren_pattern_base
-    { $$ = PatternFromParenContents(context.SourceLoc(), $1); }
+    { $$ = PatternFromParenContents(arena, context.SourceLoc(), $1); }
 ;
 paren_pattern_base:
   LEFT_PARENTHESIS paren_pattern_contents RIGHT_PARENTHESIS
@@ -465,16 +463,15 @@ paren_pattern_contents:
     { $$ = {.elements = {$1}, .has_trailing_comma = false}; }
 | paren_expression_contents COMMA paren_pattern_element
     {
-      $$ = ParenExpressionToParenPattern($1);
+      $$ = ParenExpressionToParenPattern(arena, $1);
       $$.elements.push_back($3);
     }
 | paren_pattern_contents COMMA paren_expression_element
     {
       $$ = $1;
       auto el = $3.Release();
-      $$.elements.push_back(
-          {.name = el.name,
-           .term = global_arena->New<ExpressionPattern>(el.term)});
+      $$.elements.push_back({.name = el.name,
+                             .term = arena->New<ExpressionPattern>(el.term)});
     }
 | paren_pattern_contents COMMA paren_pattern_element
     {
@@ -489,7 +486,7 @@ paren_pattern_element:
     { $$ = {.name = $1, .term = $3}; }
 ;
 tuple_pattern: paren_pattern_base
-    { $$ = TuplePatternFromParenContents(context.SourceLoc(), $1); }
+    { $$ = TuplePatternFromParenContents(arena, context.SourceLoc(), $1); }
 ;
 // Unlike most `pattern` nonterminals, this one overlaps with `expression`,
 // so it should be used only when prior context (such as an introducer)
@@ -497,8 +494,8 @@ tuple_pattern: paren_pattern_base
 maybe_empty_tuple_pattern:
   LEFT_PARENTHESIS RIGHT_PARENTHESIS
     {
-      $$ = global_arena->New<TuplePattern>(context.SourceLoc(),
-                                           std::vector<TuplePattern::Field>());
+      $$ = arena->New<TuplePattern>(context.SourceLoc(),
+                                    std::vector<TuplePattern::Field>());
     }
 | tuple_pattern
     { $$ = $1; }
@@ -508,9 +505,9 @@ clause:
     { $$ = std::pair<Ptr<const Pattern>, Ptr<const Statement>>($2, $4); }
 | DEFAULT DOUBLE_ARROW statement
     {
-      auto vp = global_arena -> New<BindingPattern>(
+      auto vp = arena -> New<BindingPattern>(
                     context.SourceLoc(), std::nullopt,
-                    global_arena->New<AutoPattern>(context.SourceLoc()));
+                    arena->New<AutoPattern>(context.SourceLoc()));
       $$ = std::pair<Ptr<const Pattern>, Ptr<const Statement>>(vp, $3);
     }
 ;
@@ -525,40 +522,39 @@ clause_list:
 ;
 statement:
   expression EQUAL expression SEMICOLON
-    { $$ = global_arena->New<Assign>(context.SourceLoc(), $1, $3); }
+    { $$ = arena->New<Assign>(context.SourceLoc(), $1, $3); }
 | VAR pattern EQUAL expression SEMICOLON
-    { $$ = global_arena->New<VariableDefinition>(context.SourceLoc(), $2, $4); }
+    { $$ = arena->New<VariableDefinition>(context.SourceLoc(), $2, $4); }
 | expression SEMICOLON
-    { $$ = global_arena->New<ExpressionStatement>(context.SourceLoc(), $1); }
+    { $$ = arena->New<ExpressionStatement>(context.SourceLoc(), $1); }
 | if_statement
     { $$ = $1; }
 | WHILE LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block
-    { $$ = global_arena->New<While>(context.SourceLoc(), $3, $5); }
+    { $$ = arena->New<While>(context.SourceLoc(), $3, $5); }
 | BREAK SEMICOLON
-    { $$ = global_arena->New<Break>(context.SourceLoc()); }
+    { $$ = arena->New<Break>(context.SourceLoc()); }
 | CONTINUE SEMICOLON
-    { $$ = global_arena->New<Continue>(context.SourceLoc()); }
+    { $$ = arena->New<Continue>(context.SourceLoc()); }
 | RETURN return_expression SEMICOLON
     {
       auto [return_exp, is_omitted_exp] = $2.Release();
-      $$ = global_arena->New<Return>(context.SourceLoc(), return_exp,
-                                     is_omitted_exp);
+      $$ = arena->New<Return>(context.SourceLoc(), return_exp, is_omitted_exp);
     }
 | block
     { $$ = $1; }
 | MATCH LEFT_PARENTHESIS expression RIGHT_PARENTHESIS LEFT_CURLY_BRACE
   clause_list RIGHT_CURLY_BRACE
-    { $$ = global_arena->New<Match>(context.SourceLoc(), $3, $6); }
+    { $$ = arena->New<Match>(context.SourceLoc(), $3, $6); }
 | CONTINUATION identifier statement
-    { $$ = global_arena->New<Continuation>(context.SourceLoc(), $2, $3); }
+    { $$ = arena->New<Continuation>(context.SourceLoc(), $2, $3); }
 | RUN expression SEMICOLON
-    { $$ = global_arena->New<Run>(context.SourceLoc(), $2); }
+    { $$ = arena->New<Run>(context.SourceLoc(), $2); }
 | AWAIT SEMICOLON
-    { $$ = global_arena->New<Await>(context.SourceLoc()); }
+    { $$ = arena->New<Await>(context.SourceLoc()); }
 ;
 if_statement:
   IF LEFT_PARENTHESIS expression RIGHT_PARENTHESIS block optional_else
-    { $$ = global_arena->New<If>(context.SourceLoc(), $3, $5, $6); }
+    { $$ = arena->New<If>(context.SourceLoc(), $3, $5, $6); }
 ;
 optional_else:
   // Empty
@@ -570,7 +566,7 @@ optional_else:
 ;
 return_expression:
   // Empty
-    { $$ = {global_arena->New<TupleLiteral>(context.SourceLoc()), true}; }
+    { $$ = {arena->New<TupleLiteral>(context.SourceLoc()), true}; }
 | expression
     { $$ = {$1, false}; }
 ;
@@ -578,15 +574,15 @@ statement_list:
   // Empty
     { $$ = std::nullopt; }
 | statement statement_list
-    { $$ = global_arena->New<Sequence>(context.SourceLoc(), $1, $2); }
+    { $$ = arena->New<Sequence>(context.SourceLoc(), $1, $2); }
 ;
 block:
   LEFT_CURLY_BRACE statement_list RIGHT_CURLY_BRACE
-    { $$ = global_arena->New<Block>(context.SourceLoc(), $2); }
+    { $$ = arena->New<Block>(context.SourceLoc(), $2); }
 ;
 return_type:
   // Empty
-    { $$ = {global_arena->New<TupleLiteral>(context.SourceLoc()), true}; }
+    { $$ = {arena->New<TupleLiteral>(context.SourceLoc()), true}; }
 | ARROW expression %prec FNARROW
     { $$ = {$2, false}; }
 ;
@@ -618,36 +614,36 @@ function_definition:
   FN identifier deduced_params maybe_empty_tuple_pattern return_type block
     {
       auto [return_exp, is_omitted_exp] = $5.Release();
-      $$ = global_arena->New<FunctionDefinition>(
+      $$ = arena->New<FunctionDefinition>(
           context.SourceLoc(), $2, $3, $4,
-          global_arena->New<ExpressionPattern>(return_exp), is_omitted_exp, $6);
+          arena->New<ExpressionPattern>(return_exp), is_omitted_exp, $6);
     }
 | FN identifier deduced_params maybe_empty_tuple_pattern DOUBLE_ARROW expression
   SEMICOLON
     {
       // The return type is not considered "omitted" because it's automatic from
       // the expression.
-      $$ = global_arena->New<FunctionDefinition>(
+      $$ = arena->New<FunctionDefinition>(
           context.SourceLoc(), $2, $3, $4,
-          global_arena->New<AutoPattern>(context.SourceLoc()), true,
-          global_arena->New<Return>(context.SourceLoc(), $6, true));
+          arena->New<AutoPattern>(context.SourceLoc()), true,
+          arena->New<Return>(context.SourceLoc(), $6, true));
     }
 ;
 function_declaration:
   FN identifier deduced_params maybe_empty_tuple_pattern return_type SEMICOLON
     {
       auto [return_exp, is_omitted_exp] = $5.Release();
-      $$ = global_arena->New<FunctionDefinition>(
+      $$ = arena->New<FunctionDefinition>(
           context.SourceLoc(), $2, $3, $4,
-          global_arena->New<ExpressionPattern>(return_exp), is_omitted_exp,
+          arena->New<ExpressionPattern>(return_exp), is_omitted_exp,
           std::nullopt);
     }
 ;
 variable_declaration: identifier COLON pattern
-    { $$ = global_arena->New<BindingPattern>(context.SourceLoc(), $1, $3); }
+    { $$ = arena->New<BindingPattern>(context.SourceLoc(), $1, $3); }
 ;
 member: VAR variable_declaration SEMICOLON
-    { $$ = global_arena->New<FieldMember>(context.SourceLoc(), $2); }
+    { $$ = arena->New<FieldMember>(context.SourceLoc(), $2); }
 ;
 member_list:
   // Empty
@@ -664,7 +660,7 @@ alternative:
 | identifier
     {
       $$ = std::pair<std::string, Ptr<const Expression>>(
-          $1, global_arena->New<TupleLiteral>(context.SourceLoc()));
+          $1, arena->New<TupleLiteral>(context.SourceLoc()));
     }
 ;
 alternative_list:
@@ -686,17 +682,15 @@ alternative_list_contents:
 ;
 declaration:
   function_definition
-    { $$ = global_arena->New<FunctionDeclaration>($1); }
+    { $$ = arena->New<FunctionDeclaration>($1); }
 | function_declaration
-    { $$ = global_arena->New<FunctionDeclaration>($1); }
+    { $$ = arena->New<FunctionDeclaration>($1); }
 | CLASS identifier LEFT_CURLY_BRACE member_list RIGHT_CURLY_BRACE
-    { $$ = global_arena->New<ClassDeclaration>(context.SourceLoc(), $2, $4); }
+    { $$ = arena->New<ClassDeclaration>(context.SourceLoc(), $2, $4); }
 | CHOICE identifier LEFT_CURLY_BRACE alternative_list RIGHT_CURLY_BRACE
-    { $$ = global_arena->New<ChoiceDeclaration>(context.SourceLoc(), $2, $4); }
+    { $$ = arena->New<ChoiceDeclaration>(context.SourceLoc(), $2, $4); }
 | VAR variable_declaration EQUAL expression SEMICOLON
-    {
-      $$ = global_arena->New<VariableDeclaration>(context.SourceLoc(), $2, $4);
-    }
+    { $$ = arena->New<VariableDeclaration>(context.SourceLoc(), $2, $4); }
 ;
 declaration_list:
   // Empty