Browse Source

Switch Expression to use inheritance+cast (#712)

Co-authored-by: Geoff Romer <gromer@google.com>
Jon Meow 4 years ago
parent
commit
dbcd6ad20d

+ 48 - 191
executable_semantics/ast/expression.cpp

@@ -9,10 +9,13 @@
 #include "executable_semantics/common/arena.h"
 #include "executable_semantics/common/error.h"
 #include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/raw_ostream.h"
 
 namespace Carbon {
 
+using llvm::cast;
+
 auto ExpressionFromParenContents(
     int line_num, const ParenContents<Expression>& paren_contents)
     -> const Expression* {
@@ -27,161 +30,10 @@ auto ExpressionFromParenContents(
 auto TupleExpressionFromParenContents(
     int line_num, const ParenContents<Expression>& paren_contents)
     -> const Expression* {
-  return Expression::MakeTupleLiteral(
+  return global_arena->New<TupleLiteral>(
       line_num, paren_contents.TupleElements<FieldInitializer>(line_num));
 }
 
-auto Expression::GetIdentifierExpression() const
-    -> const IdentifierExpression& {
-  return std::get<IdentifierExpression>(value);
-}
-
-auto Expression::GetFieldAccessExpression() const
-    -> const FieldAccessExpression& {
-  return std::get<FieldAccessExpression>(value);
-}
-
-auto Expression::GetIndexExpression() const -> const IndexExpression& {
-  return std::get<IndexExpression>(value);
-}
-
-auto Expression::GetIntLiteral() const -> int {
-  return std::get<IntLiteral>(value).value;
-}
-
-auto Expression::GetBoolLiteral() const -> bool {
-  return std::get<BoolLiteral>(value).value;
-}
-
-auto Expression::GetTupleLiteral() const -> const TupleLiteral& {
-  return std::get<TupleLiteral>(value);
-}
-
-auto Expression::GetPrimitiveOperatorExpression() const
-    -> const PrimitiveOperatorExpression& {
-  return std::get<PrimitiveOperatorExpression>(value);
-}
-
-auto Expression::GetCallExpression() const -> const CallExpression& {
-  return std::get<CallExpression>(value);
-}
-
-auto Expression::GetFunctionTypeLiteral() const -> const FunctionTypeLiteral& {
-  return std::get<FunctionTypeLiteral>(value);
-}
-
-auto Expression::MakeTypeTypeLiteral(int line_num) -> const Expression* {
-  auto* t = global_arena->New<Expression>();
-  t->line_num = line_num;
-  t->value = TypeTypeLiteral();
-  return t;
-}
-
-auto Expression::MakeIntTypeLiteral(int line_num) -> const Expression* {
-  auto* t = global_arena->New<Expression>();
-  t->line_num = line_num;
-  t->value = IntTypeLiteral();
-  return t;
-}
-
-auto Expression::MakeBoolTypeLiteral(int line_num) -> const Expression* {
-  auto* t = global_arena->New<Expression>();
-  t->line_num = line_num;
-  t->value = BoolTypeLiteral();
-  return t;
-}
-
-// Returns a Continuation type AST node at the given source location.
-auto Expression::MakeContinuationTypeLiteral(int line_num)
-    -> const Expression* {
-  auto* type = global_arena->New<Expression>();
-  type->line_num = line_num;
-  type->value = ContinuationTypeLiteral();
-  return type;
-}
-
-auto Expression::MakeFunctionTypeLiteral(int line_num,
-                                         const Expression* parameter,
-                                         const Expression* return_type,
-                                         bool is_omitted_return_type)
-    -> const Expression* {
-  auto* t = global_arena->New<Expression>();
-  t->line_num = line_num;
-  t->value =
-      FunctionTypeLiteral({.parameter = parameter,
-                           .return_type = return_type,
-                           .is_omitted_return_type = is_omitted_return_type});
-  return t;
-}
-
-auto Expression::MakeIdentifierExpression(int line_num, std::string var)
-    -> const Expression* {
-  auto* v = global_arena->New<Expression>();
-  v->line_num = line_num;
-  v->value = IdentifierExpression({.name = std::move(var)});
-  return v;
-}
-
-auto Expression::MakeIntLiteral(int line_num, int i) -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value = IntLiteral({.value = i});
-  return e;
-}
-
-auto Expression::MakeBoolLiteral(int line_num, bool b) -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value = BoolLiteral({.value = b});
-  return e;
-}
-
-auto Expression::MakePrimitiveOperatorExpression(
-    int line_num, enum Operator op, std::vector<const Expression*> args)
-    -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value =
-      PrimitiveOperatorExpression({.op = op, .arguments = std::move(args)});
-  return e;
-}
-
-auto Expression::MakeCallExpression(int line_num, const Expression* fun,
-                                    const Expression* arg)
-    -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value = CallExpression({.function = fun, .argument = arg});
-  return e;
-}
-
-auto Expression::MakeFieldAccessExpression(int line_num, const Expression* exp,
-                                           std::string field)
-    -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value =
-      FieldAccessExpression({.aggregate = exp, .field = std::move(field)});
-  return e;
-}
-
-auto Expression::MakeTupleLiteral(int line_num,
-                                  std::vector<FieldInitializer> args)
-    -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value = TupleLiteral({.fields = std::move(args)});
-  return e;
-}
-
-auto Expression::MakeIndexExpression(int line_num, const Expression* exp,
-                                     const Expression* i) -> const Expression* {
-  auto* e = global_arena->New<Expression>();
-  e->line_num = line_num;
-  e->value = IndexExpression({.aggregate = exp, .offset = i});
-  return e;
-}
-
 static void PrintOp(llvm::raw_ostream& out, Operator op) {
   switch (op) {
     case Operator::Add:
@@ -220,69 +72,74 @@ static void PrintFields(llvm::raw_ostream& out,
 }
 
 void Expression::Print(llvm::raw_ostream& out) const {
-  switch (tag()) {
-    case ExpressionKind::IndexExpression:
-      out << *GetIndexExpression().aggregate << "["
-          << *GetIndexExpression().offset << "]";
+  switch (Tag()) {
+    case Expression::Kind::IndexExpression: {
+      const auto& index = cast<IndexExpression>(*this);
+      out << *index.Aggregate() << "[" << *index.Offset() << "]";
       break;
-    case ExpressionKind::FieldAccessExpression:
-      out << *GetFieldAccessExpression().aggregate << "."
-          << GetFieldAccessExpression().field;
+    }
+    case Expression::Kind::FieldAccessExpression: {
+      const auto& access = cast<FieldAccessExpression>(*this);
+      out << *access.Aggregate() << "." << access.Field();
       break;
-    case ExpressionKind::TupleLiteral:
+    }
+    case Expression::Kind::TupleLiteral:
       out << "(";
-      PrintFields(out, GetTupleLiteral().fields);
+      PrintFields(out, cast<TupleLiteral>(*this).Fields());
       out << ")";
       break;
-    case ExpressionKind::IntLiteral:
-      out << GetIntLiteral();
+    case Expression::Kind::IntLiteral:
+      out << cast<IntLiteral>(*this).Val();
       break;
-    case ExpressionKind::BoolLiteral:
-      out << (GetBoolLiteral() ? "true" : "false");
+    case Expression::Kind::BoolLiteral:
+      out << (cast<BoolLiteral>(*this).Val() ? "true" : "false");
       break;
-    case ExpressionKind::PrimitiveOperatorExpression: {
+    case Expression::Kind::PrimitiveOperatorExpression: {
       out << "(";
-      PrimitiveOperatorExpression op = GetPrimitiveOperatorExpression();
-      if (op.arguments.size() == 0) {
-        PrintOp(out, op.op);
-      } else if (op.arguments.size() == 1) {
-        PrintOp(out, op.op);
-        out << " " << *op.arguments[0];
-      } else if (op.arguments.size() == 2) {
-        out << *op.arguments[0] << " ";
-        PrintOp(out, op.op);
-        out << " " << *op.arguments[1];
+      PrimitiveOperatorExpression op = cast<PrimitiveOperatorExpression>(*this);
+      if (op.Arguments().size() == 0) {
+        PrintOp(out, op.Op());
+      } else if (op.Arguments().size() == 1) {
+        PrintOp(out, op.Op());
+        out << " " << *op.Arguments()[0];
+      } else if (op.Arguments().size() == 2) {
+        out << *op.Arguments()[0] << " ";
+        PrintOp(out, op.Op());
+        out << " " << *op.Arguments()[1];
       }
       out << ")";
       break;
     }
-    case ExpressionKind::IdentifierExpression:
-      out << GetIdentifierExpression().name;
-      break;
-    case ExpressionKind::CallExpression:
-      out << *GetCallExpression().function;
-      if (GetCallExpression().argument->tag() == ExpressionKind::TupleLiteral) {
-        out << *GetCallExpression().argument;
+    case Expression::Kind::IdentifierExpression:
+      out << cast<IdentifierExpression>(*this).Name();
+      break;
+    case Expression::Kind::CallExpression: {
+      const auto& call = cast<CallExpression>(*this);
+      out << *call.Function();
+      if (call.Argument()->Tag() == Expression::Kind::TupleLiteral) {
+        out << *call.Argument();
       } else {
-        out << "(" << *GetCallExpression().argument << ")";
+        out << "(" << *call.Argument() << ")";
       }
       break;
-    case ExpressionKind::BoolTypeLiteral:
+    }
+    case Expression::Kind::BoolTypeLiteral:
       out << "Bool";
       break;
-    case ExpressionKind::IntTypeLiteral:
+    case Expression::Kind::IntTypeLiteral:
       out << "i32";
       break;
-    case ExpressionKind::TypeTypeLiteral:
+    case Expression::Kind::TypeTypeLiteral:
       out << "Type";
       break;
-    case ExpressionKind::ContinuationTypeLiteral:
+    case Expression::Kind::ContinuationTypeLiteral:
       out << "Continuation";
       break;
-    case ExpressionKind::FunctionTypeLiteral:
-      out << "fn " << *GetFunctionTypeLiteral().parameter << " -> "
-          << *GetFunctionTypeLiteral().return_type;
+    case Expression::Kind::FunctionTypeLiteral: {
+      const auto& fn = cast<FunctionTypeLiteral>(*this);
+      out << "fn " << *fn.Parameter() << " -> " << *fn.ReturnType();
       break;
+    }
   }
 }
 

+ 207 - 104
executable_semantics/ast/expression.h

@@ -16,8 +16,43 @@
 
 namespace Carbon {
 
-struct Expression;
-class Pattern;
+class Expression {
+ public:
+  enum class Kind {
+    BoolTypeLiteral,
+    BoolLiteral,
+    CallExpression,
+    FunctionTypeLiteral,
+    FieldAccessExpression,
+    IndexExpression,
+    IntTypeLiteral,
+    ContinuationTypeLiteral,  // The type of a continuation value.
+    IntLiteral,
+    PrimitiveOperatorExpression,
+    TupleLiteral,
+    TypeTypeLiteral,
+    IdentifierExpression,
+  };
+
+  // Returns the enumerator corresponding to the most-derived type of this
+  // object.
+  auto Tag() const -> Kind { return tag; }
+
+  auto LineNumber() const -> int { return line_num; }
+
+  void Print(llvm::raw_ostream& out) const;
+  LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
+
+ protected:
+  // Constructs an Expression representing syntax at the given line number.
+  // `tag` must be the enumerator corresponding to the most-derived type being
+  // constructed.
+  Expression(Kind tag, int line_num) : tag(tag), line_num(line_num) {}
+
+ private:
+  const Kind tag;
+  int line_num;
+};
 
 // Converts paren_contents to an Expression, interpreting the parentheses as
 // grouping if their contents permit that interpretation, or as forming a
@@ -44,22 +79,6 @@ struct FieldInitializer {
   const Expression* expression;
 };
 
-enum class ExpressionKind {
-  BoolTypeLiteral,
-  BoolLiteral,
-  CallExpression,
-  FunctionTypeLiteral,
-  FieldAccessExpression,
-  IndexExpression,
-  IntTypeLiteral,
-  ContinuationTypeLiteral,  // The type of a continuation value.
-  IntLiteral,
-  PrimitiveOperatorExpression,
-  TupleLiteral,
-  TypeTypeLiteral,
-  IdentifierExpression,
-};
-
 enum class Operator {
   Add,
   And,
@@ -73,129 +92,213 @@ enum class Operator {
   Ptr,
 };
 
-struct Expression;
+class IdentifierExpression : public Expression {
+ public:
+  explicit IdentifierExpression(int line_num, std::string name)
+      : Expression(Kind::IdentifierExpression, line_num),
+        name(std::move(name)) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::IdentifierExpression;
+  }
+
+  auto Name() const -> const std::string& { return name; }
 
-struct IdentifierExpression {
-  static constexpr ExpressionKind Kind = ExpressionKind::IdentifierExpression;
+ private:
   std::string name;
 };
 
-struct FieldAccessExpression {
-  static constexpr ExpressionKind Kind = ExpressionKind::FieldAccessExpression;
+class FieldAccessExpression : public Expression {
+ public:
+  explicit FieldAccessExpression(int line_num, const Expression* aggregate,
+                                 std::string field)
+      : Expression(Kind::FieldAccessExpression, line_num),
+        aggregate(aggregate),
+        field(std::move(field)) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::FieldAccessExpression;
+  }
+
+  auto Aggregate() const -> const Expression* { return aggregate; }
+  auto Field() const -> const std::string& { return field; }
+
+ private:
   const Expression* aggregate;
   std::string field;
 };
 
-struct IndexExpression {
-  static constexpr ExpressionKind Kind = ExpressionKind::IndexExpression;
+class IndexExpression : public Expression {
+ public:
+  explicit IndexExpression(int line_num, const Expression* aggregate,
+                           const Expression* offset)
+      : Expression(Kind::IndexExpression, line_num),
+        aggregate(aggregate),
+        offset(offset) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::IndexExpression;
+  }
+
+  auto Aggregate() const -> const Expression* { return aggregate; }
+  auto Offset() const -> const Expression* { return offset; }
+
+ private:
   const Expression* aggregate;
   const Expression* offset;
 };
 
-struct IntLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::IntLiteral;
-  int value;
+class IntLiteral : public Expression {
+ public:
+  explicit IntLiteral(int line_num, int val)
+      : Expression(Kind::IntLiteral, line_num), val(val) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::IntLiteral;
+  }
+
+  auto Val() const -> int { return val; }
+
+ private:
+  int val;
 };
 
-struct BoolLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::BoolLiteral;
-  bool value;
+class BoolLiteral : public Expression {
+ public:
+  explicit BoolLiteral(int line_num, bool val)
+      : Expression(Kind::BoolLiteral, line_num), val(val) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::BoolLiteral;
+  }
+
+  auto Val() const -> bool { return val; }
+
+ private:
+  bool val;
 };
 
-struct TupleLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::TupleLiteral;
+class TupleLiteral : public Expression {
+ public:
+  explicit TupleLiteral(int line_num) : TupleLiteral(line_num, {}) {}
+
+  explicit TupleLiteral(int line_num, std::vector<FieldInitializer> fields)
+      : Expression(Kind::TupleLiteral, line_num), fields(std::move(fields)) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::TupleLiteral;
+  }
+
+  auto Fields() const -> const std::vector<FieldInitializer>& { return fields; }
+
+ private:
   std::vector<FieldInitializer> fields;
 };
 
-struct PrimitiveOperatorExpression {
-  static constexpr ExpressionKind Kind =
-      ExpressionKind::PrimitiveOperatorExpression;
+class PrimitiveOperatorExpression : public Expression {
+ public:
+  explicit PrimitiveOperatorExpression(int line_num, Operator op,
+                                       std::vector<const Expression*> arguments)
+      : Expression(Kind::PrimitiveOperatorExpression, line_num),
+        op(op),
+        arguments(std::move(arguments)) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::PrimitiveOperatorExpression;
+  }
+
+  auto Op() const -> Operator { return op; }
+  auto Arguments() const -> const std::vector<const Expression*>& {
+    return arguments;
+  }
+
+ private:
   Operator op;
   std::vector<const Expression*> arguments;
 };
 
-struct CallExpression {
-  static constexpr ExpressionKind Kind = ExpressionKind::CallExpression;
+class CallExpression : public Expression {
+ public:
+  explicit CallExpression(int line_num, const Expression* function,
+                          const Expression* argument)
+      : Expression(Kind::CallExpression, line_num),
+        function(function),
+        argument(argument) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::CallExpression;
+  }
+
+  auto Function() const -> const Expression* { return function; }
+  auto Argument() const -> const Expression* { return argument; }
+
+ private:
   const Expression* function;
   const Expression* argument;
 };
 
-struct FunctionTypeLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::FunctionTypeLiteral;
+class FunctionTypeLiteral : public Expression {
+ public:
+  explicit FunctionTypeLiteral(int line_num, const Expression* parameter,
+                               const Expression* return_type,
+                               bool is_omitted_return_type)
+      : Expression(Kind::FunctionTypeLiteral, line_num),
+        parameter(parameter),
+        return_type(return_type),
+        is_omitted_return_type(is_omitted_return_type) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::FunctionTypeLiteral;
+  }
+
+  auto Parameter() const -> const Expression* { return parameter; }
+  auto ReturnType() const -> const Expression* { return return_type; }
+  auto IsOmittedReturnType() const -> bool { return is_omitted_return_type; }
+
+ private:
   const Expression* parameter;
   const Expression* return_type;
   bool is_omitted_return_type;
 };
 
-struct BoolTypeLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::BoolTypeLiteral;
-};
-
-struct IntTypeLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::IntTypeLiteral;
-};
-
-struct ContinuationTypeLiteral {
-  static constexpr ExpressionKind Kind =
-      ExpressionKind::ContinuationTypeLiteral;
-};
-
-struct TypeTypeLiteral {
-  static constexpr ExpressionKind Kind = ExpressionKind::TypeTypeLiteral;
-};
-
-struct Expression {
-  static auto MakeIdentifierExpression(int line_num, std::string var)
-      -> const Expression*;
-  static auto MakeIntLiteral(int line_num, int i) -> const Expression*;
-  static auto MakeBoolLiteral(int line_num, bool b) -> const Expression*;
-  static auto MakePrimitiveOperatorExpression(
-      int line_num, Operator op, std::vector<const Expression*> args)
-      -> const Expression*;
-  static auto MakeCallExpression(int line_num, const Expression* fun,
-                                 const Expression* arg) -> const Expression*;
-  static auto MakeFieldAccessExpression(int line_num, const Expression* exp,
-                                        std::string field) -> const Expression*;
-  static auto MakeTupleLiteral(int line_num, std::vector<FieldInitializer> args)
-      -> const Expression*;
-  static auto MakeIndexExpression(int line_num, const Expression* exp,
-                                  const Expression* i) -> const Expression*;
-  static auto MakeTypeTypeLiteral(int line_num) -> const Expression*;
-  static auto MakeIntTypeLiteral(int line_num) -> const Expression*;
-  static auto MakeBoolTypeLiteral(int line_num) -> const Expression*;
-  static auto MakeFunctionTypeLiteral(int line_num, const Expression* parameter,
-                                      const Expression* return_type,
-                                      bool is_omitted_return_type)
-      -> const Expression*;
-  static auto MakeContinuationTypeLiteral(int line_num) -> const Expression*;
-
-  auto GetIdentifierExpression() const -> const IdentifierExpression&;
-  auto GetFieldAccessExpression() const -> const FieldAccessExpression&;
-  auto GetIndexExpression() const -> const IndexExpression&;
-  auto GetIntLiteral() const -> int;
-  auto GetBoolLiteral() const -> bool;
-  auto GetTupleLiteral() const -> const TupleLiteral&;
-  auto GetPrimitiveOperatorExpression() const
-      -> const PrimitiveOperatorExpression&;
-  auto GetCallExpression() const -> const CallExpression&;
-  auto GetFunctionTypeLiteral() const -> const FunctionTypeLiteral&;
+class BoolTypeLiteral : public Expression {
+ public:
+  explicit BoolTypeLiteral(int line_num)
+      : Expression(Kind::BoolTypeLiteral, line_num) {}
 
-  void Print(llvm::raw_ostream& out) const;
-  LLVM_DUMP_METHOD void Dump() const { Print(llvm::errs()); }
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::BoolTypeLiteral;
+  }
+};
+
+class IntTypeLiteral : public Expression {
+ public:
+  explicit IntTypeLiteral(int line_num)
+      : Expression(Kind::IntTypeLiteral, line_num) {}
 
-  inline auto tag() const -> ExpressionKind {
-    return std::visit([](const auto& t) { return t.Kind; }, value);
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::IntTypeLiteral;
   }
+};
 
-  int line_num;
+class ContinuationTypeLiteral : public Expression {
+ public:
+  explicit ContinuationTypeLiteral(int line_num)
+      : Expression(Kind::ContinuationTypeLiteral, line_num) {}
 
- private:
-  std::variant<IdentifierExpression, FieldAccessExpression, IndexExpression,
-               IntLiteral, BoolLiteral, TupleLiteral,
-               PrimitiveOperatorExpression, CallExpression, FunctionTypeLiteral,
-               BoolTypeLiteral, IntTypeLiteral, ContinuationTypeLiteral,
-               TypeTypeLiteral>
-      value;
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::ContinuationTypeLiteral;
+  }
+};
+
+class TypeTypeLiteral : public Expression {
+ public:
+  explicit TypeTypeLiteral(int line_num)
+      : Expression(Kind::TypeTypeLiteral, line_num) {}
+
+  static auto classof(const Expression* exp) -> bool {
+    return exp->Tag() == Kind::TypeTypeLiteral;
+  }
 };
 
 }  // namespace Carbon

+ 37 - 32
executable_semantics/ast/expression_test.cpp

@@ -6,13 +6,16 @@
 
 #include <string>
 
+#include "executable_semantics/common/arena.h"
 #include "executable_semantics/syntax/paren_contents.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "llvm/Support/Casting.h"
 
 namespace Carbon {
 namespace {
 
+using llvm::cast;
 using testing::ElementsAre;
 using testing::IsEmpty;
 
@@ -20,7 +23,7 @@ using testing::IsEmpty;
 // `IntLiteral`
 MATCHER_P(IntFieldNamed, name, "") {
   return arg.name == std::string(name) &&
-         arg.expression->tag() == ExpressionKind::IntLiteral;
+         arg.expression->Tag() == Expression::Kind::IntLiteral;
 }
 
 TEST(ExpressionTest, EmptyAsExpression) {
@@ -28,9 +31,9 @@ TEST(ExpressionTest, EmptyAsExpression) {
                                         .has_trailing_comma = false};
   const Expression* expression =
       ExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(expression->line_num, 1);
-  ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(expression->GetTupleLiteral().fields, IsEmpty());
+  EXPECT_EQ(expression->LineNumber(), 1);
+  ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(), IsEmpty());
 }
 
 TEST(ExpressionTest, EmptyAsTuple) {
@@ -38,9 +41,9 @@ TEST(ExpressionTest, EmptyAsTuple) {
                                         .has_trailing_comma = false};
   const Expression* tuple =
       TupleExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(tuple->line_num, 1);
-  ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(tuple->GetTupleLiteral().fields, IsEmpty());
+  EXPECT_EQ(tuple->LineNumber(), 1);
+  ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(), IsEmpty());
 }
 
 TEST(ExpressionTest, UnaryNoCommaAsExpression) {
@@ -52,84 +55,86 @@ TEST(ExpressionTest, UnaryNoCommaAsExpression) {
   // ```
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
       .has_trailing_comma = false};
 
   const Expression* expression =
       ExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(expression->line_num, 2);
-  ASSERT_EQ(expression->tag(), ExpressionKind::IntLiteral);
+  EXPECT_EQ(expression->LineNumber(), 2);
+  ASSERT_EQ(expression->Tag(), Expression::Kind::IntLiteral);
 }
 
 TEST(ExpressionTest, UnaryNoCommaAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
       .has_trailing_comma = false};
 
   const Expression* tuple =
       TupleExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(tuple->line_num, 1);
-  ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(tuple->GetTupleLiteral().fields, ElementsAre(IntFieldNamed("0")));
+  EXPECT_EQ(tuple->LineNumber(), 1);
+  ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
+              ElementsAre(IntFieldNamed("0")));
 }
 
 TEST(ExpressionTest, UnaryWithCommaAsExpression) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
       .has_trailing_comma = true};
 
   const Expression* expression =
       ExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(expression->line_num, 1);
-  ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(expression->GetTupleLiteral().fields,
+  EXPECT_EQ(expression->LineNumber(), 1);
+  ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
               ElementsAre(IntFieldNamed("0")));
 }
 
 TEST(ExpressionTest, UnaryWithCommaAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)}},
       .has_trailing_comma = true};
 
   const Expression* tuple =
       TupleExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(tuple->line_num, 1);
-  ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(tuple->GetTupleLiteral().fields, ElementsAre(IntFieldNamed("0")));
+  EXPECT_EQ(tuple->LineNumber(), 1);
+  ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
+              ElementsAre(IntFieldNamed("0")));
 }
 
 TEST(ExpressionTest, BinaryAsExpression) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)},
                    {.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/3, 42)}},
       .has_trailing_comma = true};
 
   const Expression* expression =
       ExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(expression->line_num, 1);
-  ASSERT_EQ(expression->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(expression->GetTupleLiteral().fields,
+  EXPECT_EQ(expression->LineNumber(), 1);
+  ASSERT_EQ(expression->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*expression).Fields(),
               ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
 }
 
 TEST(ExpressionTest, BinaryAsTuple) {
   ParenContents<Expression> contents = {
       .elements = {{.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/2, 42)},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/2, 42)},
                    {.name = std::nullopt,
-                    .term = Expression::MakeIntLiteral(/*line_num=*/3, 42)}},
+                    .term = global_arena->New<IntLiteral>(/*line_num=*/3, 42)}},
       .has_trailing_comma = true};
 
   const Expression* tuple =
       TupleExpressionFromParenContents(/*line_num=*/1, contents);
-  EXPECT_EQ(tuple->line_num, 1);
-  ASSERT_EQ(tuple->tag(), ExpressionKind::TupleLiteral);
-  EXPECT_THAT(tuple->GetTupleLiteral().fields,
+  EXPECT_EQ(tuple->LineNumber(), 1);
+  ASSERT_EQ(tuple->Tag(), Expression::Kind::TupleLiteral);
+  EXPECT_THAT(cast<TupleLiteral>(*tuple).Fields(),
               ElementsAre(IntFieldNamed("0"), IntFieldNamed("1")));
 }
 

+ 8 - 8
executable_semantics/ast/pattern.cpp

@@ -55,9 +55,9 @@ void Pattern::Print(llvm::raw_ostream& out) const {
 }
 
 TuplePattern::TuplePattern(const Expression* tuple_literal)
-    : Pattern(Kind::TuplePattern, tuple_literal->line_num) {
-  const auto& tuple = tuple_literal->GetTupleLiteral();
-  for (const FieldInitializer& init : tuple.fields) {
+    : Pattern(Kind::TuplePattern, tuple_literal->LineNumber()) {
+  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)));
   }
@@ -85,13 +85,13 @@ AlternativePattern::AlternativePattern(int line_num,
                                        const Expression* alternative,
                                        const TuplePattern* arguments)
     : Pattern(Kind::AlternativePattern, line_num), arguments(arguments) {
-  if (alternative->tag() != ExpressionKind::FieldAccessExpression) {
-    FATAL_PROGRAM_ERROR(alternative->line_num)
+  if (alternative->Tag() != Expression::Kind::FieldAccessExpression) {
+    FATAL_PROGRAM_ERROR(alternative->LineNumber())
         << "Alternative pattern must have the form of a field access.";
   }
-  const auto& field_access = alternative->GetFieldAccessExpression();
-  choice_type = field_access.aggregate;
-  alternative_name = field_access.field;
+  const auto& field_access = cast<FieldAccessExpression>(*alternative);
+  choice_type = field_access.Aggregate();
+  alternative_name = field_access.Field();
 }
 
 auto ParenExpressionToParenPattern(const ParenContents<Expression>& contents)

+ 2 - 2
executable_semantics/ast/pattern.h

@@ -111,7 +111,7 @@ class TuplePattern : public Pattern {
   // Converts tuple_literal to a TuplePattern, by wrapping each field in an
   // ExpressionPattern.
   //
-  // REQUIRES: tuple_literal->Tag() == ExpressionKind::TupleLiteral
+  // REQUIRES: tuple_literal->Tag() == Expression::Kind::TupleLiteral
   explicit TuplePattern(const Expression* tuple_literal);
 
   static auto classof(const Pattern* pattern) -> bool {
@@ -182,7 +182,7 @@ class AlternativePattern : public Pattern {
 class ExpressionPattern : public Pattern {
  public:
   ExpressionPattern(const Expression* expression)
-      : Pattern(Kind::ExpressionPattern, expression->line_num),
+      : Pattern(Kind::ExpressionPattern, expression->LineNumber()),
         expression(expression) {}
 
   static auto classof(const Pattern* pattern) -> bool {

+ 1 - 1
executable_semantics/ast/statement.cpp

@@ -123,7 +123,7 @@ auto Statement::MakeReturn(int line_num, const Expression* exp,
   s->line_num = line_num;
   if (exp == nullptr) {
     CHECK(is_omitted_exp);
-    exp = Expression::MakeTupleLiteral(line_num, {});
+    exp = global_arena->New<TupleLiteral>(line_num);
   }
   s->value = Return({.exp = exp, .is_omitted_exp = is_omitted_exp});
   return s;

+ 77 - 76
executable_semantics/interpreter/interpreter.cpp

@@ -243,12 +243,12 @@ void DeallocateLocals(int line_num, Frame* frame) {
 void CreateTuple(Frame* frame, Action* act, const Expression* exp) {
   //    { { (v1,...,vn) :: C, E, F} :: S, H}
   // -> { { `(v1,...,vn) :: C, E, F} :: S, H}
-  const auto& tup_lit = exp->GetTupleLiteral();
-  CHECK(act->Results().size() == tup_lit.fields.size());
+  const auto& tup_lit = cast<TupleLiteral>(*exp);
+  CHECK(act->Results().size() == tup_lit.Fields().size());
   std::vector<TupleElement> elements;
   for (size_t i = 0; i < act->Results().size(); ++i) {
     elements.push_back(
-        {.name = tup_lit.fields[i].name, .value = act->Results()[i]});
+        {.name = tup_lit.Fields()[i].name, .value = act->Results()[i]});
   }
 
   const Value* tv = global_arena->New<TupleValue>(std::move(elements));
@@ -407,50 +407,51 @@ void StepLvalue() {
   if (tracing_output) {
     llvm::outs() << "--- step lvalue " << *exp << " --->\n";
   }
-  switch (exp->tag()) {
-    case ExpressionKind::IdentifierExpression: {
+  switch (exp->Tag()) {
+    case Expression::Kind::IdentifierExpression: {
       //    { {x :: C, E, F} :: S, H}
       // -> { {E(x) :: C, E, F} :: S, H}
       std::optional<Address> pointer =
-          CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
+          CurrentEnv(state).Get(cast<IdentifierExpression>(*exp).Name());
       if (!pointer) {
-        FATAL_RUNTIME_ERROR(exp->line_num)
-            << "could not find `" << exp->GetIdentifierExpression().name << "`";
+        FATAL_RUNTIME_ERROR(exp->LineNumber())
+            << "could not find `" << cast<IdentifierExpression>(*exp).Name()
+            << "`";
       }
       const Value* v = global_arena->New<PointerValue>(*pointer);
       frame->todo.Pop();
       frame->todo.Push(global_arena->New<ValAction>(v));
       break;
     }
-    case ExpressionKind::FieldAccessExpression: {
+    case Expression::Kind::FieldAccessExpression: {
       if (act->Pos() == 0) {
         //    { {e.f :: C, E, F} :: S, H}
         // -> { e :: [].f :: C, E, F} :: S, H}
         frame->todo.Push(global_arena->New<LValAction>(
-            exp->GetFieldAccessExpression().aggregate));
+            cast<FieldAccessExpression>(*exp).Aggregate()));
         act->IncrementPos();
       } else {
         //    { v :: [].f :: C, E, F} :: S, H}
         // -> { { &v.f :: C, E, F} :: S, H }
         Address aggregate = cast<PointerValue>(*act->Results()[0]).Val();
-        Address field =
-            aggregate.SubobjectAddress(exp->GetFieldAccessExpression().field);
+        Address field = aggregate.SubobjectAddress(
+            cast<FieldAccessExpression>(*exp).Field());
         frame->todo.Pop(1);
         frame->todo.Push(global_arena->New<ValAction>(
             global_arena->New<PointerValue>(field)));
       }
       break;
     }
-    case ExpressionKind::IndexExpression: {
+    case Expression::Kind::IndexExpression: {
       if (act->Pos() == 0) {
         //    { {e[i] :: C, E, F} :: S, H}
         // -> { e :: [][i] :: C, E, F} :: S, H}
-        frame->todo.Push(
-            global_arena->New<LValAction>(exp->GetIndexExpression().aggregate));
+        frame->todo.Push(global_arena->New<LValAction>(
+            cast<IndexExpression>(*exp).Aggregate()));
         act->IncrementPos();
       } else if (act->Pos() == 1) {
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetIndexExpression().offset));
+            cast<IndexExpression>(*exp).Offset()));
         act->IncrementPos();
       } else if (act->Pos() == 2) {
         //    { v :: [][i] :: C, E, F} :: S, H}
@@ -465,21 +466,21 @@ void StepLvalue() {
       }
       break;
     }
-    case ExpressionKind::TupleLiteral: {
+    case Expression::Kind::TupleLiteral: {
       if (act->Pos() == 0) {
         //    { {(f1=e1,...) :: C, E, F} :: S, H}
         // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
-        const Expression* e1 = exp->GetTupleLiteral().fields[0].expression;
+        const Expression* e1 = cast<TupleLiteral>(*exp).Fields()[0].expression;
         frame->todo.Push(global_arena->New<LValAction>(e1));
         act->IncrementPos();
       } else if (act->Pos() !=
-                 static_cast<int>(exp->GetTupleLiteral().fields.size())) {
+                 static_cast<int>(cast<TupleLiteral>(*exp).Fields().size())) {
         //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
         //    H}
         // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
         // H}
         const Expression* elt =
-            exp->GetTupleLiteral().fields[act->Pos()].expression;
+            cast<TupleLiteral>(*exp).Fields()[act->Pos()].expression;
         frame->todo.Push(global_arena->New<LValAction>(elt));
         act->IncrementPos();
       } else {
@@ -487,15 +488,15 @@ void StepLvalue() {
       }
       break;
     }
-    case ExpressionKind::IntLiteral:
-    case ExpressionKind::BoolLiteral:
-    case ExpressionKind::CallExpression:
-    case ExpressionKind::PrimitiveOperatorExpression:
-    case ExpressionKind::IntTypeLiteral:
-    case ExpressionKind::BoolTypeLiteral:
-    case ExpressionKind::TypeTypeLiteral:
-    case ExpressionKind::FunctionTypeLiteral:
-    case ExpressionKind::ContinuationTypeLiteral: {
+    case Expression::Kind::IntLiteral:
+    case Expression::Kind::BoolLiteral:
+    case Expression::Kind::CallExpression:
+    case Expression::Kind::PrimitiveOperatorExpression:
+    case Expression::Kind::IntTypeLiteral:
+    case Expression::Kind::BoolTypeLiteral:
+    case Expression::Kind::TypeTypeLiteral:
+    case Expression::Kind::FunctionTypeLiteral:
+    case Expression::Kind::ContinuationTypeLiteral: {
       FATAL_RUNTIME_ERROR_NO_LINE()
           << "Can't treat expression as lvalue: " << *exp;
     }
@@ -511,17 +512,17 @@ void StepExp() {
   if (tracing_output) {
     llvm::outs() << "--- step exp " << *exp << " --->\n";
   }
-  switch (exp->tag()) {
-    case ExpressionKind::IndexExpression: {
+  switch (exp->Tag()) {
+    case Expression::Kind::IndexExpression: {
       if (act->Pos() == 0) {
         //    { { e[i] :: C, E, F} :: S, H}
         // -> { { e :: [][i] :: C, E, F} :: S, H}
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetIndexExpression().aggregate));
+            cast<IndexExpression>(*exp).Aggregate()));
         act->IncrementPos();
       } else if (act->Pos() == 1) {
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetIndexExpression().offset));
+            cast<IndexExpression>(*exp).Offset()));
         act->IncrementPos();
       } else if (act->Pos() == 2) {
         auto tuple = act->Results()[0];
@@ -547,25 +548,26 @@ void StepExp() {
       }
       break;
     }
-    case ExpressionKind::TupleLiteral: {
+    case Expression::Kind::TupleLiteral: {
       if (act->Pos() == 0) {
-        if (exp->GetTupleLiteral().fields.size() > 0) {
+        if (cast<TupleLiteral>(*exp).Fields().size() > 0) {
           //    { {(f1=e1,...) :: C, E, F} :: S, H}
           // -> { {e1 :: (f1=[],...) :: C, E, F} :: S, H}
-          const Expression* e1 = exp->GetTupleLiteral().fields[0].expression;
+          const Expression* e1 =
+              cast<TupleLiteral>(*exp).Fields()[0].expression;
           frame->todo.Push(global_arena->New<ExpressionAction>(e1));
           act->IncrementPos();
         } else {
           CreateTuple(frame, act, exp);
         }
       } else if (act->Pos() !=
-                 static_cast<int>(exp->GetTupleLiteral().fields.size())) {
+                 static_cast<int>(cast<TupleLiteral>(*exp).Fields().size())) {
         //    { { vk :: (f1=v1,..., fk=[],fk+1=ek+1,...) :: C, E, F} :: S,
         //    H}
         // -> { { ek+1 :: (f1=v1,..., fk=vk, fk+1=[],...) :: C, E, F} :: S,
         // H}
         const Expression* elt =
-            exp->GetTupleLiteral().fields[act->Pos()].expression;
+            cast<TupleLiteral>(*exp).Fields()[act->Pos()].expression;
         frame->todo.Push(global_arena->New<ExpressionAction>(elt));
         act->IncrementPos();
       } else {
@@ -573,123 +575,122 @@ void StepExp() {
       }
       break;
     }
-    case ExpressionKind::FieldAccessExpression: {
+    case Expression::Kind::FieldAccessExpression: {
+      const auto& access = cast<FieldAccessExpression>(*exp);
       if (act->Pos() == 0) {
         //    { { e.f :: C, E, F} :: S, H}
         // -> { { e :: [].f :: C, E, F} :: S, H}
-        frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetFieldAccessExpression().aggregate));
+        frame->todo.Push(
+            global_arena->New<ExpressionAction>(access.Aggregate()));
         act->IncrementPos();
       } else {
         //    { { v :: [].f :: C, E, F} :: S, H}
         // -> { { v_f :: C, E, F} : S, H}
         const Value* element = act->Results()[0]->GetField(
-            FieldPath(exp->GetFieldAccessExpression().field), exp->line_num);
+            FieldPath(access.Field()), exp->LineNumber());
         frame->todo.Pop(1);
         frame->todo.Push(global_arena->New<ValAction>(element));
       }
       break;
     }
-    case ExpressionKind::IdentifierExpression: {
+    case Expression::Kind::IdentifierExpression: {
       CHECK(act->Pos() == 0);
+      const auto& ident = cast<IdentifierExpression>(*exp);
       // { {x :: C, E, F} :: S, H} -> { {H(E(x)) :: C, E, F} :: S, H}
-      std::optional<Address> pointer =
-          CurrentEnv(state).Get(exp->GetIdentifierExpression().name);
+      std::optional<Address> pointer = CurrentEnv(state).Get(ident.Name());
       if (!pointer) {
-        FATAL_RUNTIME_ERROR(exp->line_num)
-            << "could not find `" << exp->GetIdentifierExpression().name << "`";
+        FATAL_RUNTIME_ERROR(exp->LineNumber())
+            << "could not find `" << ident.Name() << "`";
       }
-      const Value* pointee = state->heap.Read(*pointer, exp->line_num);
+      const Value* pointee = state->heap.Read(*pointer, exp->LineNumber());
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(pointee));
       break;
     }
-    case ExpressionKind::IntLiteral:
+    case Expression::Kind::IntLiteral:
       CHECK(act->Pos() == 0);
       // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(
-          global_arena->New<IntValue>(exp->GetIntLiteral())));
+          global_arena->New<IntValue>(cast<IntLiteral>(*exp).Val())));
       break;
-    case ExpressionKind::BoolLiteral:
+    case Expression::Kind::BoolLiteral:
       CHECK(act->Pos() == 0);
       // { {n :: C, E, F} :: S, H} -> { {n' :: C, E, F} :: S, H}
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(
-          global_arena->New<BoolValue>(exp->GetBoolLiteral())));
+          global_arena->New<BoolValue>(cast<BoolLiteral>(*exp).Val())));
       break;
-    case ExpressionKind::PrimitiveOperatorExpression:
-      if (act->Pos() !=
-          static_cast<int>(
-              exp->GetPrimitiveOperatorExpression().arguments.size())) {
+    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}
-        const Expression* arg =
-            exp->GetPrimitiveOperatorExpression().arguments[act->Pos()];
+        const Expression* arg = op.Arguments()[act->Pos()];
         frame->todo.Push(global_arena->New<ExpressionAction>(arg));
         act->IncrementPos();
       } else {
         //    { {v :: op(vs,[]) :: C, E, F} :: S, H}
         // -> { {eval_prim(op, (vs,v)) :: C, E, F} :: S, H}
-        const Value* v = EvalPrim(exp->GetPrimitiveOperatorExpression().op,
-                                  act->Results(), exp->line_num);
+        const Value* v = EvalPrim(op.Op(), act->Results(), exp->LineNumber());
         frame->todo.Pop(1);
         frame->todo.Push(global_arena->New<ValAction>(v));
       }
       break;
-    case ExpressionKind::CallExpression:
+    }
+    case Expression::Kind::CallExpression:
       if (act->Pos() == 0) {
         //    { {e1(e2) :: C, E, F} :: S, H}
         // -> { {e1 :: [](e2) :: C, E, F} :: S, H}
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetCallExpression().function));
+            cast<CallExpression>(*exp).Function()));
         act->IncrementPos();
       } else if (act->Pos() == 1) {
         //    { { v :: [](e) :: C, E, F} :: S, H}
         // -> { { e :: v([]) :: C, E, F} :: S, H}
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetCallExpression().argument));
+            cast<CallExpression>(*exp).Argument()));
         act->IncrementPos();
       } else if (act->Pos() == 2) {
         //    { { v2 :: v1([]) :: C, E, F} :: S, H}
         // -> { {C',E',F'} :: {C, E, F} :: S, H}
         frame->todo.Pop(1);
-        CallFunction(exp->line_num, act->Results(), state);
+        CallFunction(exp->LineNumber(), act->Results(), state);
       } else {
         FATAL() << "in handle_value with Call pos " << act->Pos();
       }
       break;
-    case ExpressionKind::IntTypeLiteral: {
+    case Expression::Kind::IntTypeLiteral: {
       CHECK(act->Pos() == 0);
       const Value* v = global_arena->New<IntType>();
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(v));
       break;
     }
-    case ExpressionKind::BoolTypeLiteral: {
+    case Expression::Kind::BoolTypeLiteral: {
       CHECK(act->Pos() == 0);
       const Value* v = global_arena->New<BoolType>();
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(v));
       break;
     }
-    case ExpressionKind::TypeTypeLiteral: {
+    case Expression::Kind::TypeTypeLiteral: {
       CHECK(act->Pos() == 0);
       const Value* v = global_arena->New<TypeType>();
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(v));
       break;
     }
-    case ExpressionKind::FunctionTypeLiteral: {
+    case Expression::Kind::FunctionTypeLiteral: {
       if (act->Pos() == 0) {
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetFunctionTypeLiteral().parameter));
+            cast<FunctionTypeLiteral>(*exp).Parameter()));
         act->IncrementPos();
       } else if (act->Pos() == 1) {
         //    { { pt :: fn [] -> e :: C, E, F} :: S, H}
         // -> { { e :: fn pt -> []) :: C, E, F} :: S, H}
         frame->todo.Push(global_arena->New<ExpressionAction>(
-            exp->GetFunctionTypeLiteral().return_type));
+            cast<FunctionTypeLiteral>(*exp).ReturnType()));
         act->IncrementPos();
       } else if (act->Pos() == 2) {
         //    { { rt :: fn pt -> [] :: C, E, F} :: S, H}
@@ -702,14 +703,14 @@ void StepExp() {
       }
       break;
     }
-    case ExpressionKind::ContinuationTypeLiteral: {
+    case Expression::Kind::ContinuationTypeLiteral: {
       CHECK(act->Pos() == 0);
       const Value* v = global_arena->New<ContinuationType>();
       frame->todo.Pop(1);
       frame->todo.Push(global_arena->New<ValAction>(v));
       break;
     }
-  }  // switch (exp->tag)
+  }  // switch (exp->Tag)
 }
 
 void StepPattern() {
@@ -1124,7 +1125,7 @@ void StepStmt() {
         Action* ignore_result = global_arena->New<StatementAction>(
             Statement::MakeExpressionStatement(
                 stmt->line_num,
-                Expression::MakeTupleLiteral(stmt->line_num, {})));
+                global_arena->New<TupleLiteral>(stmt->line_num)));
         frame->todo.Push(ignore_result);
         // Push the continuation onto the current stack.
         const std::vector<Frame*>& continuation_vector =
@@ -1190,9 +1191,9 @@ auto InterpProgram(const std::list<const Declaration*>& fs) -> int {
   }
   InitGlobals(fs);
 
-  const Expression* arg = Expression::MakeTupleLiteral(0, {});
-  const Expression* call_main = Expression::MakeCallExpression(
-      0, Expression::MakeIdentifierExpression(0, "main"), arg);
+  const Expression* arg = global_arena->New<TupleLiteral>(0);
+  const Expression* call_main = global_arena->New<CallExpression>(
+      0, global_arena->New<IdentifierExpression>(0, "main"), arg);
   auto todo = Stack<Action*>(global_arena->New<ExpressionAction>(call_main));
   auto* scope = global_arena->New<Scope>(globals, std::list<std::string>());
   auto* frame = global_arena->New<Frame>("top", Stack(scope), todo);

+ 108 - 103
executable_semantics/interpreter/typecheck.cpp

@@ -46,16 +46,16 @@ static void ExpectPointerType(int line_num, const std::string& context,
 static auto ReifyType(const Value* t, int line_num) -> const Expression* {
   switch (t->Tag()) {
     case Value::Kind::IntType:
-      return Expression::MakeIntTypeLiteral(0);
+      return global_arena->New<IntTypeLiteral>(0);
     case Value::Kind::BoolType:
-      return Expression::MakeBoolTypeLiteral(0);
+      return global_arena->New<BoolTypeLiteral>(0);
     case Value::Kind::TypeType:
-      return Expression::MakeTypeTypeLiteral(0);
+      return global_arena->New<TypeTypeLiteral>(0);
     case Value::Kind::ContinuationType:
-      return Expression::MakeContinuationTypeLiteral(0);
+      return global_arena->New<ContinuationTypeLiteral>(0);
     case Value::Kind::FunctionType: {
       const auto& fn_type = cast<FunctionType>(*t);
-      return Expression::MakeFunctionTypeLiteral(
+      return global_arena->New<FunctionTypeLiteral>(
           0, ReifyType(fn_type.Param(), line_num),
           ReifyType(fn_type.Ret(), line_num),
           /*is_omitted_return_type=*/false);
@@ -66,20 +66,21 @@ static auto ReifyType(const Value* t, int line_num) -> const Expression* {
         args.push_back(
             FieldInitializer(field.name, ReifyType(field.value, line_num)));
       }
-      return Expression::MakeTupleLiteral(0, args);
+      return global_arena->New<TupleLiteral>(0, args);
     }
     case Value::Kind::StructType:
-      return Expression::MakeIdentifierExpression(0,
-                                                  cast<StructType>(*t).Name());
+      return global_arena->New<IdentifierExpression>(
+          0, cast<StructType>(*t).Name());
     case Value::Kind::ChoiceType:
-      return Expression::MakeIdentifierExpression(0,
-                                                  cast<ChoiceType>(*t).Name());
+      return global_arena->New<IdentifierExpression>(
+          0, cast<ChoiceType>(*t).Name());
     case Value::Kind::PointerType:
-      return Expression::MakePrimitiveOperatorExpression(
+      return global_arena->New<PrimitiveOperatorExpression>(
           0, Operator::Ptr,
-          {ReifyType(cast<PointerType>(*t).Type(), line_num)});
+          std::vector<const Expression*>(
+              {ReifyType(cast<PointerType>(*t).Type(), line_num)}));
     case Value::Kind::VariableType:
-      return Expression::MakeIdentifierExpression(
+      return global_arena->New<IdentifierExpression>(
           0, cast<VariableType>(*t).Name());
     default:
       FATAL() << "expected a type, not " << *t;
@@ -245,202 +246,204 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values)
   if (tracing_output) {
     llvm::outs() << "checking expression " << *e << "\n";
   }
-  switch (e->tag()) {
-    case ExpressionKind::IndexExpression: {
-      auto res = TypeCheckExp(e->GetIndexExpression().aggregate, types, values);
+  switch (e->Tag()) {
+    case Expression::Kind::IndexExpression: {
+      const auto& index = cast<IndexExpression>(*e);
+      auto res = TypeCheckExp(index.Aggregate(), types, values);
       auto t = res.type;
       switch (t->Tag()) {
         case Value::Kind::TupleValue: {
-          auto i =
-              cast<IntValue>(*InterpExp(values, e->GetIndexExpression().offset))
-                  .Val();
+          auto i = cast<IntValue>(*InterpExp(values, index.Offset())).Val();
           std::string f = std::to_string(i);
           const Value* field_t = cast<TupleValue>(*t).FindField(f);
           if (field_t == nullptr) {
-            FATAL_COMPILATION_ERROR(e->line_num)
+            FATAL_COMPILATION_ERROR(e->LineNumber())
                 << "field " << f << " is not in the tuple " << *t;
           }
-          auto new_e = Expression::MakeIndexExpression(
-              e->line_num, res.exp, Expression::MakeIntLiteral(e->line_num, i));
+          auto new_e = global_arena->New<IndexExpression>(
+              e->LineNumber(), res.exp,
+              global_arena->New<IntLiteral>(e->LineNumber(), i));
           return TCExpression(new_e, field_t, res.types);
         }
         default:
-          FATAL_COMPILATION_ERROR(e->line_num) << "expected a tuple";
+          FATAL_COMPILATION_ERROR(e->LineNumber()) << "expected a tuple";
       }
     }
-    case ExpressionKind::TupleLiteral: {
+    case Expression::Kind::TupleLiteral: {
       std::vector<FieldInitializer> new_args;
       std::vector<TupleElement> arg_types;
       auto new_types = types;
-      int i = 0;
-      for (auto arg = e->GetTupleLiteral().fields.begin();
-           arg != e->GetTupleLiteral().fields.end(); ++arg, ++i) {
-        auto arg_res = TypeCheckExp(arg->expression, new_types, values);
+      for (const auto& arg : cast<TupleLiteral>(*e).Fields()) {
+        auto arg_res = TypeCheckExp(arg.expression, new_types, values);
         new_types = arg_res.types;
-        new_args.push_back(FieldInitializer(arg->name, arg_res.exp));
-        arg_types.push_back({.name = arg->name, .value = arg_res.type});
+        new_args.push_back(FieldInitializer(arg.name, arg_res.exp));
+        arg_types.push_back({.name = arg.name, .value = arg_res.type});
       }
-      auto tuple_e = Expression::MakeTupleLiteral(e->line_num, new_args);
+      auto tuple_e = global_arena->New<TupleLiteral>(e->LineNumber(), new_args);
       auto tuple_t = global_arena->New<TupleValue>(std::move(arg_types));
       return TCExpression(tuple_e, tuple_t, new_types);
     }
-    case ExpressionKind::FieldAccessExpression: {
-      auto res =
-          TypeCheckExp(e->GetFieldAccessExpression().aggregate, types, values);
+    case Expression::Kind::FieldAccessExpression: {
+      const auto& access = cast<FieldAccessExpression>(*e);
+      auto res = TypeCheckExp(access.Aggregate(), types, values);
       auto t = res.type;
       switch (t->Tag()) {
         case Value::Kind::StructType: {
           const auto& t_struct = cast<StructType>(*t);
           // Search for a field
           for (auto& field : t_struct.Fields()) {
-            if (e->GetFieldAccessExpression().field == field.first) {
-              const Expression* new_e = Expression::MakeFieldAccessExpression(
-                  e->line_num, res.exp, e->GetFieldAccessExpression().field);
+            if (access.Field() == field.first) {
+              const Expression* new_e =
+                  global_arena->New<FieldAccessExpression>(
+                      e->LineNumber(), res.exp, access.Field());
               return TCExpression(new_e, field.second, res.types);
             }
           }
           // Search for a method
           for (auto& method : t_struct.Methods()) {
-            if (e->GetFieldAccessExpression().field == method.first) {
-              const Expression* new_e = Expression::MakeFieldAccessExpression(
-                  e->line_num, res.exp, e->GetFieldAccessExpression().field);
+            if (access.Field() == method.first) {
+              const Expression* new_e =
+                  global_arena->New<FieldAccessExpression>(
+                      e->LineNumber(), res.exp, access.Field());
               return TCExpression(new_e, method.second, res.types);
             }
           }
-          FATAL_COMPILATION_ERROR(e->line_num)
+          FATAL_COMPILATION_ERROR(e->LineNumber())
               << "struct " << t_struct.Name() << " does not have a field named "
-              << e->GetFieldAccessExpression().field;
+              << access.Field();
         }
         case Value::Kind::TupleValue: {
           const auto& tup = cast<TupleValue>(*t);
           for (const TupleElement& field : tup.Elements()) {
-            if (e->GetFieldAccessExpression().field == field.name) {
-              auto new_e = Expression::MakeFieldAccessExpression(
-                  e->line_num, res.exp, e->GetFieldAccessExpression().field);
+            if (access.Field() == field.name) {
+              auto new_e = global_arena->New<FieldAccessExpression>(
+                  e->LineNumber(), res.exp, access.Field());
               return TCExpression(new_e, field.value, res.types);
             }
           }
-          FATAL_COMPILATION_ERROR(e->line_num)
+          FATAL_COMPILATION_ERROR(e->LineNumber())
               << "tuple " << tup << " does not have a field named "
-              << e->GetFieldAccessExpression().field;
+              << access.Field();
         }
         case Value::Kind::ChoiceType: {
           const auto& choice = cast<ChoiceType>(*t);
           for (const auto& vt : choice.Alternatives()) {
-            if (e->GetFieldAccessExpression().field == vt.first) {
-              const Expression* new_e = Expression::MakeFieldAccessExpression(
-                  e->line_num, res.exp, e->GetFieldAccessExpression().field);
+            if (access.Field() == vt.first) {
+              const Expression* new_e =
+                  global_arena->New<FieldAccessExpression>(
+                      e->LineNumber(), res.exp, access.Field());
               auto fun_ty = global_arena->New<FunctionType>(
                   std::vector<GenericBinding>(), vt.second, t);
               return TCExpression(new_e, fun_ty, res.types);
             }
           }
-          FATAL_COMPILATION_ERROR(e->line_num)
+          FATAL_COMPILATION_ERROR(e->LineNumber())
               << "choice " << choice.Name() << " does not have a field named "
-              << e->GetFieldAccessExpression().field;
+              << access.Field();
         }
         default:
-          FATAL_COMPILATION_ERROR(e->line_num)
+          FATAL_COMPILATION_ERROR(e->LineNumber())
               << "field access, expected a struct\n"
               << *e;
       }
     }
-    case ExpressionKind::IdentifierExpression: {
-      std::optional<const Value*> type =
-          types.Get(e->GetIdentifierExpression().name);
+    case Expression::Kind::IdentifierExpression: {
+      const auto& ident = cast<IdentifierExpression>(*e);
+      std::optional<const Value*> type = types.Get(ident.Name());
       if (type) {
         return TCExpression(e, *type, types);
       } else {
-        FATAL_COMPILATION_ERROR(e->line_num)
-            << "could not find `" << e->GetIdentifierExpression().name << "`";
+        FATAL_COMPILATION_ERROR(e->LineNumber())
+            << "could not find `" << ident.Name() << "`";
       }
     }
-    case ExpressionKind::IntLiteral:
+    case Expression::Kind::IntLiteral:
       return TCExpression(e, global_arena->New<IntType>(), types);
-    case ExpressionKind::BoolLiteral:
+    case Expression::Kind::BoolLiteral:
       return TCExpression(e, global_arena->New<BoolType>(), types);
-    case ExpressionKind::PrimitiveOperatorExpression: {
+    case Expression::Kind::PrimitiveOperatorExpression: {
+      const auto& op = cast<PrimitiveOperatorExpression>(*e);
       std::vector<const Expression*> es;
       std::vector<const Value*> ts;
       auto new_types = types;
-      for (const Expression* argument :
-           e->GetPrimitiveOperatorExpression().arguments) {
+      for (const Expression* argument : op.Arguments()) {
         auto res = TypeCheckExp(argument, types, values);
         new_types = res.types;
         es.push_back(res.exp);
         ts.push_back(res.type);
       }
-      auto new_e = Expression::MakePrimitiveOperatorExpression(
-          e->line_num, e->GetPrimitiveOperatorExpression().op, es);
-      switch (e->GetPrimitiveOperatorExpression().op) {
+      auto new_e = global_arena->New<PrimitiveOperatorExpression>(
+          e->LineNumber(), op.Op(), es);
+      switch (op.Op()) {
         case Operator::Neg:
-          ExpectType(e->line_num, "negation", global_arena->New<IntType>(),
+          ExpectType(e->LineNumber(), "negation", global_arena->New<IntType>(),
                      ts[0]);
           return TCExpression(new_e, global_arena->New<IntType>(), new_types);
         case Operator::Add:
-          ExpectType(e->line_num, "addition(1)", global_arena->New<IntType>(),
-                     ts[0]);
-          ExpectType(e->line_num, "addition(2)", global_arena->New<IntType>(),
-                     ts[1]);
+          ExpectType(e->LineNumber(), "addition(1)",
+                     global_arena->New<IntType>(), ts[0]);
+          ExpectType(e->LineNumber(), "addition(2)",
+                     global_arena->New<IntType>(), ts[1]);
           return TCExpression(new_e, global_arena->New<IntType>(), new_types);
         case Operator::Sub:
-          ExpectType(e->line_num, "subtraction(1)",
+          ExpectType(e->LineNumber(), "subtraction(1)",
                      global_arena->New<IntType>(), ts[0]);
-          ExpectType(e->line_num, "subtraction(2)",
+          ExpectType(e->LineNumber(), "subtraction(2)",
                      global_arena->New<IntType>(), ts[1]);
           return TCExpression(new_e, global_arena->New<IntType>(), new_types);
         case Operator::Mul:
-          ExpectType(e->line_num, "multiplication(1)",
+          ExpectType(e->LineNumber(), "multiplication(1)",
                      global_arena->New<IntType>(), ts[0]);
-          ExpectType(e->line_num, "multiplication(2)",
+          ExpectType(e->LineNumber(), "multiplication(2)",
                      global_arena->New<IntType>(), ts[1]);
           return TCExpression(new_e, global_arena->New<IntType>(), new_types);
         case Operator::And:
-          ExpectType(e->line_num, "&&(1)", global_arena->New<BoolType>(),
+          ExpectType(e->LineNumber(), "&&(1)", global_arena->New<BoolType>(),
                      ts[0]);
-          ExpectType(e->line_num, "&&(2)", global_arena->New<BoolType>(),
+          ExpectType(e->LineNumber(), "&&(2)", global_arena->New<BoolType>(),
                      ts[1]);
           return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
         case Operator::Or:
-          ExpectType(e->line_num, "||(1)", global_arena->New<BoolType>(),
+          ExpectType(e->LineNumber(), "||(1)", global_arena->New<BoolType>(),
                      ts[0]);
-          ExpectType(e->line_num, "||(2)", global_arena->New<BoolType>(),
+          ExpectType(e->LineNumber(), "||(2)", global_arena->New<BoolType>(),
                      ts[1]);
           return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
         case Operator::Not:
-          ExpectType(e->line_num, "!", global_arena->New<BoolType>(), ts[0]);
+          ExpectType(e->LineNumber(), "!", global_arena->New<BoolType>(),
+                     ts[0]);
           return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
         case Operator::Eq:
-          ExpectType(e->line_num, "==", ts[0], ts[1]);
+          ExpectType(e->LineNumber(), "==", ts[0], ts[1]);
           return TCExpression(new_e, global_arena->New<BoolType>(), new_types);
         case Operator::Deref:
-          ExpectPointerType(e->line_num, "*", ts[0]);
+          ExpectPointerType(e->LineNumber(), "*", ts[0]);
           return TCExpression(new_e, cast<PointerType>(*ts[0]).Type(),
                               new_types);
         case Operator::Ptr:
-          ExpectType(e->line_num, "*", global_arena->New<TypeType>(), ts[0]);
+          ExpectType(e->LineNumber(), "*", global_arena->New<TypeType>(),
+                     ts[0]);
           return TCExpression(new_e, global_arena->New<TypeType>(), new_types);
       }
       break;
     }
-    case ExpressionKind::CallExpression: {
-      auto fun_res =
-          TypeCheckExp(e->GetCallExpression().function, types, values);
+    case Expression::Kind::CallExpression: {
+      const auto& call = cast<CallExpression>(*e);
+      auto fun_res = TypeCheckExp(call.Function(), types, values);
       switch (fun_res.type->Tag()) {
         case Value::Kind::FunctionType: {
           const auto& fun_t = cast<FunctionType>(*fun_res.type);
-          auto arg_res = TypeCheckExp(e->GetCallExpression().argument,
-                                      fun_res.types, values);
+          auto arg_res = TypeCheckExp(call.Argument(), fun_res.types, values);
           auto parameter_type = fun_t.Param();
           auto return_type = fun_t.Ret();
           if (!fun_t.Deduced().empty()) {
-            auto deduced_args = ArgumentDeduction(e->line_num, TypeEnv(),
+            auto deduced_args = ArgumentDeduction(e->LineNumber(), TypeEnv(),
                                                   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.
               if (!deduced_args.Get(deduced_param.name)) {
-                FATAL_COMPILATION_ERROR(e->line_num)
+                FATAL_COMPILATION_ERROR(e->LineNumber())
                     << "could not deduce type argument for type parameter "
                     << deduced_param.name;
               }
@@ -448,35 +451,37 @@ auto TypeCheckExp(const Expression* e, TypeEnv types, Env values)
             parameter_type = Substitute(deduced_args, parameter_type);
             return_type = Substitute(deduced_args, return_type);
           } else {
-            ExpectType(e->line_num, "call", parameter_type, arg_res.type);
+            ExpectType(e->LineNumber(), "call", parameter_type, arg_res.type);
           }
-          auto new_e = Expression::MakeCallExpression(e->line_num, fun_res.exp,
-                                                      arg_res.exp);
+          auto new_e = global_arena->New<CallExpression>(
+              e->LineNumber(), fun_res.exp, arg_res.exp);
           return TCExpression(new_e, return_type, arg_res.types);
         }
         default: {
-          FATAL_COMPILATION_ERROR(e->line_num)
+          FATAL_COMPILATION_ERROR(e->LineNumber())
               << "in call, expected a function\n"
               << *e;
         }
       }
       break;
     }
-    case ExpressionKind::FunctionTypeLiteral: {
-      auto pt = InterpExp(values, e->GetFunctionTypeLiteral().parameter);
-      auto rt = InterpExp(values, e->GetFunctionTypeLiteral().return_type);
-      auto new_e = Expression::MakeFunctionTypeLiteral(
-          e->line_num, ReifyType(pt, e->line_num), ReifyType(rt, e->line_num),
+    case Expression::Kind::FunctionTypeLiteral: {
+      const auto& fn = cast<FunctionTypeLiteral>(*e);
+      auto pt = InterpExp(values, fn.Parameter());
+      auto rt = InterpExp(values, fn.ReturnType());
+      auto new_e = global_arena->New<FunctionTypeLiteral>(
+          e->LineNumber(), ReifyType(pt, e->LineNumber()),
+          ReifyType(rt, e->LineNumber()),
           /*is_omitted_return_type=*/false);
       return TCExpression(new_e, global_arena->New<TypeType>(), types);
     }
-    case ExpressionKind::IntTypeLiteral:
+    case Expression::Kind::IntTypeLiteral:
       return TCExpression(e, global_arena->New<TypeType>(), types);
-    case ExpressionKind::BoolTypeLiteral:
+    case Expression::Kind::BoolTypeLiteral:
       return TCExpression(e, global_arena->New<TypeType>(), types);
-    case ExpressionKind::TypeTypeLiteral:
+    case Expression::Kind::TypeTypeLiteral:
       return TCExpression(e, global_arena->New<TypeType>(), types);
-    case ExpressionKind::ContinuationTypeLiteral:
+    case Expression::Kind::ContinuationTypeLiteral:
       return TCExpression(e, global_arena->New<TypeType>(), types);
   }
 }

+ 39 - 39
executable_semantics/syntax/parser.ypp

@@ -211,71 +211,71 @@ input: declaration_list
 ;
 expression:
   identifier
-    { $$ = Expression::MakeIdentifierExpression(yylineno, $1); }
+    { $$ = global_arena->New<IdentifierExpression>(yylineno, $1); }
 | expression designator
-    { $$ = Expression::MakeFieldAccessExpression(yylineno, $1, $2); }
+    { $$ = global_arena->New<FieldAccessExpression>(yylineno, $1, $2); }
 | expression "[" expression "]"
-    { $$ = Expression::MakeIndexExpression(yylineno, $1, $3); }
+    { $$ = global_arena->New<IndexExpression>(yylineno, $1, $3); }
 | integer_literal
-    { $$ = Expression::MakeIntLiteral(yylineno, $1); }
+    { $$ = global_arena->New<IntLiteral>(yylineno, $1); }
 | TRUE
-    { $$ = Expression::MakeBoolLiteral(yylineno, true); }
+    { $$ = global_arena->New<BoolLiteral>(yylineno, true); }
 | FALSE
-    { $$ = Expression::MakeBoolLiteral(yylineno, false); }
+    { $$ = global_arena->New<BoolLiteral>(yylineno, 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;
-      $$ = Expression::MakeIntTypeLiteral(yylineno);
+      $$ = global_arena->New<IntTypeLiteral>(yylineno);
     }
 | BOOL
-    { $$ = Expression::MakeBoolTypeLiteral(yylineno); }
+    { $$ = global_arena->New<BoolTypeLiteral>(yylineno); }
 | TYPE
-    { $$ = Expression::MakeTypeTypeLiteral(yylineno); }
+    { $$ = global_arena->New<TypeTypeLiteral>(yylineno); }
 | CONTINUATION_TYPE
-    { $$ = Expression::MakeContinuationTypeLiteral(yylineno); }
+    { $$ = global_arena->New<ContinuationTypeLiteral>(yylineno); }
 | paren_expression { $$ = $1; }
 | expression EQUAL_EQUAL expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Eq, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Eq, std::vector<const Expression*>({$1, $3})); }
 | expression "+" expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Add, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Add, std::vector<const Expression*>({$1, $3})); }
 | expression "-" expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Sub, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Sub, std::vector<const Expression*>({$1, $3})); }
 | expression BINARY_STAR expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Mul, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Mul, std::vector<const Expression*>({$1, $3})); }
 | expression AND expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::And, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::And, std::vector<const Expression*>({$1, $3})); }
 | expression OR expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Or, {$1, $3}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Or, std::vector<const Expression*>({$1, $3})); }
 | NOT expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Not, {$2}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Not, std::vector<const Expression*>({$2})); }
 | "-" expression %prec UNARY_MINUS
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Neg, {$2}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Neg, std::vector<const Expression*>({$2})); }
 | PREFIX_STAR expression
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Deref, {$2}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Deref, std::vector<const Expression*>({$2})); }
 | UNARY_STAR expression %prec PREFIX_STAR
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Deref, {$2}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Deref, std::vector<const Expression*>({$2})); }
 | expression tuple
-    { $$ = Expression::MakeCallExpression(yylineno, $1, $2); }
+    { $$ = global_arena->New<CallExpression>(yylineno, $1, $2); }
 | expression POSTFIX_STAR
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Ptr, {$1}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Ptr, std::vector<const Expression*>({$1})); }
 | expression UNARY_STAR
-    { $$ = Expression::MakePrimitiveOperatorExpression(
-        yylineno, Operator::Ptr, {$1}); }
+    { $$ = global_arena->New<PrimitiveOperatorExpression>(
+        yylineno, Operator::Ptr, std::vector<const Expression*>({$1})); }
 | FNTY tuple return_type
-    { $$ = Expression::MakeFunctionTypeLiteral(
+    { $$ = global_arena->New<FunctionTypeLiteral>(
         yylineno, $2, $3.first, $3.second); }
 ;
 designator: "." identifier { $$ = $2; }
@@ -454,7 +454,7 @@ optional_else:
 ;
 return_expression:
   // Empty
-    { $$ = {Expression::MakeTupleLiteral(yylineno, {}), true}; }
+    { $$ = {global_arena->New<TupleLiteral>(yylineno), true}; }
 | expression
     { $$ = {$1, false}; }
 ;
@@ -470,7 +470,7 @@ block:
 ;
 return_type:
   // Empty
-    { $$ = {Expression::MakeTupleLiteral(yylineno, {}), true}; }
+    { $$ = {global_arena->New<TupleLiteral>(yylineno), true}; }
 | ARROW expression %prec FNARROW
     { $$ = {$2, false}; }
 ;
@@ -544,7 +544,7 @@ alternative:
 | identifier
     {
       $$ = std::pair<std::string, const Expression*>(
-          $1, Expression::MakeTupleLiteral(yylineno, {}));
+          $1, global_arena->New<TupleLiteral>(yylineno));
     }
 ;
 alternative_list: