Start cleaning up tests (4/N)

Remove Source{} with ast::Builder::create<>
Use Builder helpers where possible

Change-Id: I07fdefdbbcc4a9289069e2e494f475c7baea7531
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35741
Auto-Submit: Ben Clayton <bclayton@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/builder.cc b/src/ast/builder.cc
index f9b96a7..612bc9e 100644
--- a/src/ast/builder.cc
+++ b/src/ast/builder.cc
@@ -75,6 +75,18 @@
   return var;
 }
 
+Variable* Builder::Const(const Source& source,
+                         const std::string& name,
+                         StorageClass storage,
+                         type::Type* type,
+                         Expression* constructor,
+                         VariableDecorationList decorations) {
+  auto* var = create<Variable>(source, name, storage, type, true, constructor,
+                               decorations);
+  OnVariableBuilt(var);
+  return var;
+}
+
 BuilderWithModule::BuilderWithModule() : Builder(new Module()) {}
 
 BuilderWithModule::~BuilderWithModule() {
diff --git a/src/ast/builder.h b/src/ast/builder.h
index a4f4b64..05afa92 100644
--- a/src/ast/builder.h
+++ b/src/ast/builder.h
@@ -499,6 +499,20 @@
                   Expression* constructor,
                   VariableDecorationList decorations);
 
+  /// @param source the variable source
+  /// @param name the variable name
+  /// @param storage the variable storage class
+  /// @param type the variable type
+  /// @param constructor optional constructor expression
+  /// @param decorations optional variable decorations
+  /// @returns a constant `Variable` with the given name, storage and type
+  Variable* Const(const Source& source,
+                  const std::string& name,
+                  StorageClass storage,
+                  type::Type* type,
+                  Expression* constructor,
+                  VariableDecorationList decorations);
+
   /// @param func the function name
   /// @param args the function call arguments
   /// @returns a `CallExpression` to the function `func`, with the
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index 65e644b..3a7c2f0 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -17,6 +17,7 @@
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "src/ast/builder.h"
 #include "src/ast/function.h"
 #include "src/ast/pipeline_stage.h"
 #include "src/ast/stage_decoration.h"
@@ -34,10 +35,9 @@
 namespace transform {
 namespace {
 
-class VertexPullingHelper {
+class VertexPullingHelper : public ast::BuilderWithModule {
  public:
   VertexPullingHelper() {
-    mod_ = std::make_unique<ast::Module>();
     manager_ = std::make_unique<Manager>();
     auto transform = std::make_unique<VertexPulling>();
     transform_ = transform.get();
@@ -47,19 +47,19 @@
   // Create basic module with an entry point and vertex function
   void InitBasicModule() {
     auto* func = create<ast::Function>(
-        Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{},
-        mod_->create<ast::type::Void>(),
-        create<ast::BlockStatement>(Source{}, ast::StatementList{}),
-        ast::FunctionDecorationList{create<ast::StageDecoration>(
-            Source{}, ast::PipelineStage::kVertex)});
-    mod()->AddFunction(func);
+        mod->RegisterSymbol("main"), "main", ast::VariableList{},
+        mod->create<ast::type::Void>(),
+        create<ast::BlockStatement>(ast::StatementList{}),
+        ast::FunctionDecorationList{
+            create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
+    mod->AddFunction(func);
   }
 
   // Set up the transformation, after building the module
   void InitTransform(VertexStateDescriptor vertex_state) {
-    EXPECT_TRUE(mod_->IsValid());
+    EXPECT_TRUE(mod->IsValid());
 
-    TypeDeterminer td(mod_.get());
+    TypeDeterminer td(mod);
     EXPECT_TRUE(td.Determine());
 
     transform_->SetVertexState(vertex_state);
@@ -70,37 +70,18 @@
   void AddVertexInputVariable(uint32_t location,
                               std::string name,
                               ast::type::Type* type) {
-    auto* var = create<ast::Variable>(
-        Source{},                   // source
-        name,                       // name
-        ast::StorageClass::kInput,  // storage_class
-        type,                       // type
-        false,                      // is_const
-        nullptr,                    // constructor
-        ast::VariableDecorationList{
-            // decorations
-            create<ast::LocationDecoration>(Source{}, location),
-        });
+    auto* var = Var(name, ast::StorageClass::kInput, type, nullptr,
+                    ast::VariableDecorationList{
+                        create<ast::LocationDecoration>(location),
+                    });
 
-    mod_->AddGlobalVariable(var);
+    mod->AddGlobalVariable(var);
   }
 
-  ast::Module* mod() { return mod_.get(); }
-
   Manager* manager() { return manager_.get(); }
   VertexPulling* transform() { return transform_; }
 
-  /// Creates a new `ast::Node` owned by the Module. When the Module is
-  /// destructed, the `ast::Node` will also be destructed.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  T* create(ARGS&&... args) {
-    return mod_->create<T>(std::forward<ARGS>(args)...);
-  }
-
  private:
-  std::unique_ptr<ast::Module> mod_;
   std::unique_ptr<Manager> manager_;
   VertexPulling* transform_;
 };
@@ -108,7 +89,7 @@
 class VertexPullingTest : public VertexPullingHelper, public testing::Test {};
 
 TEST_F(VertexPullingTest, Error_NoVertexState) {
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   EXPECT_TRUE(result.diagnostics.contains_errors());
   EXPECT_EQ(diag::Formatter().format(result.diagnostics),
             "error: SetVertexState not called");
@@ -116,7 +97,7 @@
 
 TEST_F(VertexPullingTest, Error_NoEntryPoint) {
   transform()->SetVertexState({});
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   EXPECT_TRUE(result.diagnostics.contains_errors());
   EXPECT_EQ(diag::Formatter().format(result.diagnostics),
             "error: Vertex stage entry point not found");
@@ -127,7 +108,7 @@
   InitTransform({});
   transform()->SetEntryPoint("_");
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   EXPECT_TRUE(result.diagnostics.contains_errors());
   EXPECT_EQ(diag::Formatter().format(result.diagnostics),
             "error: Vertex stage entry point not found");
@@ -135,16 +116,16 @@
 
 TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
   auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{},
-      mod()->create<ast::type::Void>(),
-      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      mod->RegisterSymbol("main"), "main", ast::VariableList{},
+      mod->create<ast::type::Void>(),
+      create<ast::BlockStatement>(ast::StatementList{}),
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
+          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   InitTransform({});
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   EXPECT_TRUE(result.diagnostics.contains_errors());
   EXPECT_EQ(diag::Formatter().format(result.diagnostics),
             "error: Vertex stage entry point not found");
@@ -153,7 +134,7 @@
 TEST_F(VertexPullingTest, BasicModule) {
   InitBasicModule();
   InitTransform({});
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 }
@@ -166,7 +147,7 @@
 
   InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}});
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
@@ -253,7 +234,7 @@
   InitTransform(
       {{{4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 0}}}}});
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
@@ -340,7 +321,7 @@
   InitTransform({{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}}}});
   transform()->SetPullingBufferBindingSet(5);
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
@@ -428,35 +409,23 @@
 
   ast::type::I32 i32;
 
-  mod()->AddGlobalVariable(create<ast::Variable>(
-      Source{},                   // source
-      "custom_vertex_index",      // name
-      ast::StorageClass::kInput,  // storage_class
-      &i32,                       // type
-      false,                      // is_const
-      nullptr,                    // constructor
-      ast::VariableDecorationList{
-          // decorations
-          create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kVertexIdx),
-      }));
+  mod->AddGlobalVariable(
+      Var("custom_vertex_index", ast::StorageClass::kInput, &i32, nullptr,
+          ast::VariableDecorationList{
+              create<ast::BuiltinDecoration>(ast::Builtin::kVertexIdx),
+          }));
 
-  mod()->AddGlobalVariable(create<ast::Variable>(
-      Source{},                   // source
-      "custom_instance_index",    // name
-      ast::StorageClass::kInput,  // storage_class
-      &i32,                       // type
-      false,                      // is_const
-      nullptr,                    // constructor
-      ast::VariableDecorationList{
-          // decorations
-          create<ast::BuiltinDecoration>(Source{}, ast::Builtin::kInstanceIdx),
-      }));
+  mod->AddGlobalVariable(
+      Var("custom_instance_index", ast::StorageClass::kInput, &i32, nullptr,
+          ast::VariableDecorationList{
+              create<ast::BuiltinDecoration>(ast::Builtin::kInstanceIdx),
+          }));
 
   InitTransform(
       {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}},
         {4, InputStepMode::kInstance, {{VertexFormat::kF32, 0, 1}}}}});
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
@@ -598,7 +567,7 @@
          InputStepMode::kVertex,
          {{VertexFormat::kF32, 0, 0}, {VertexFormat::kVec4F32, 0, 1}}}}});
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
@@ -785,7 +754,7 @@
         {12, InputStepMode::kVertex, {{VertexFormat::kVec3F32, 0, 1}}},
         {16, InputStepMode::kVertex, {{VertexFormat::kVec4F32, 0, 2}}}}});
 
-  auto result = manager()->Run(mod());
+  auto result = manager()->Run(mod);
   ASSERT_FALSE(result.diagnostics.contains_errors())
       << diag::Formatter().format(result.diagnostics);
 
diff --git a/src/validator/validator_control_block_test.cc b/src/validator/validator_control_block_test.cc
index 0cbd07b..8009eef 100644
--- a/src/validator/validator_control_block_test.cc
+++ b/src/validator/validator_control_block_test.cc
@@ -42,32 +42,20 @@
   // switch (a) {
   //   default: {}
   // }
-  ast::type::F32 f32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &f32, 3.14f)),  // constructor
-      ast::VariableDecorationList{});                        // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.14f),
+                  ast::VariableDecorationList{});
 
   auto* cond = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a");
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("a"), "a");
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
   ast::CaseStatementList body;
-  body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, body),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -81,33 +69,21 @@
   // switch (a) {
   //   case 1: {}
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
   ast::CaseSelectorList csl;
-  csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
+  csl.push_back(Literal(1));
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(
-      Source{}, csl,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      csl, create<ast::BlockStatement>(ast::StatementList{})));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(
-                        Source{Source::Location{12, 34}}, cond, body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(Source{Source::Location{12, 34}}, cond,
+                                   body),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -123,47 +99,32 @@
   //   case 1: {}
   //   default: {}
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
   ast::CaseStatementList switch_body;
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
 
   ast::CaseSelectorList default_csl_1;
-  auto* block_default_1 =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
+  auto* block_default_1 = create<ast::BlockStatement>(ast::StatementList{});
   switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl_1, block_default_1));
+      create<ast::CaseStatement>(default_csl_1, block_default_1));
 
   ast::CaseSelectorList csl_case_1;
-  csl_case_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
-  auto* block_case_1 =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, csl_case_1, block_case_1));
+  csl_case_1.push_back(Literal(1));
+  auto* block_case_1 = create<ast::BlockStatement>(ast::StatementList{});
+  switch_body.push_back(create<ast::CaseStatement>(csl_case_1, block_case_1));
 
   ast::CaseSelectorList default_csl_2;
-  auto* block_default_2 =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
+  auto* block_default_2 = create<ast::BlockStatement>(ast::StatementList{});
   switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl_2, block_default_2));
+      create<ast::CaseStatement>(default_csl_2, block_default_2));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(
-                        Source{Source::Location{12, 34}}, cond, switch_body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(Source{Source::Location{12, 34}}, cond,
+                                   switch_body),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -179,40 +140,26 @@
   //   case 1: {}
   //   default: {}
   // }
-  ast::type::U32 u32;
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
   ast::CaseStatementList switch_body;
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
 
   ast::CaseSelectorList csl;
-  csl.push_back(create<ast::UintLiteral>(Source{}, &u32, 1));
+  csl.push_back(create<ast::UintLiteral>(ty.u32, 1));
   switch_body.push_back(create<ast::CaseStatement>(
       Source{Source::Location{12, 34}}, csl,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
+  switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, switch_body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -227,40 +174,28 @@
   //   case -1: {}
   //   default: {}
   // }
-  ast::type::U32 u32;
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &u32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::UintLiteral>(Source{}, &u32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.u32,
+                  create<ast::ScalarConstructorExpression>(
+                      create<ast::UintLiteral>(ty.u32, 2)),
+                  ast::VariableDecorationList{});
 
   ast::CaseStatementList switch_body;
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
 
   ast::CaseSelectorList csl;
-  csl.push_back(create<ast::SintLiteral>(Source{}, &i32, -1));
+  csl.push_back(Literal(-1));
   switch_body.push_back(create<ast::CaseStatement>(
       Source{Source::Location{12, 34}}, csl,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
+  switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, switch_body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -275,46 +210,34 @@
   //   case 2, 2: {}
   //   default: {}
   // }
-  ast::type::U32 u32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &u32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::UintLiteral>(Source{}, &u32, 3)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.u32,
+                  create<ast::ScalarConstructorExpression>(
+                      create<ast::UintLiteral>(ty.u32, 3)),
+                  ast::VariableDecorationList{});
 
   ast::CaseStatementList switch_body;
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
 
   ast::CaseSelectorList csl_1;
-  csl_1.push_back(create<ast::UintLiteral>(Source{}, &u32, 0));
+  csl_1.push_back(create<ast::UintLiteral>(ty.u32, 0));
   switch_body.push_back(create<ast::CaseStatement>(
-      Source{}, csl_1,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      csl_1, create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList csl_2;
-  csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2));
-  csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2));
+  csl_2.push_back(create<ast::UintLiteral>(ty.u32, 2));
+  csl_2.push_back(create<ast::UintLiteral>(ty.u32, 2));
   switch_body.push_back(create<ast::CaseStatement>(
       Source{Source::Location{12, 34}}, csl_2,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
+  switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, switch_body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -329,48 +252,34 @@
   //   case 0,1,2,10: {}
   //   default: {}
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
   ast::CaseStatementList switch_body;
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
 
   ast::CaseSelectorList csl_1;
-  csl_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 10));
+  csl_1.push_back(Literal(10));
   switch_body.push_back(create<ast::CaseStatement>(
-      Source{}, csl_1,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      csl_1, create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList csl_2;
-  csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 0));
-  csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
-  csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 2));
-  csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 10));
+  csl_2.push_back(Literal(0));
+  csl_2.push_back(Literal(1));
+  csl_2.push_back(Literal(2));
+  csl_2.push_back(Literal(10));
   switch_body.push_back(create<ast::CaseStatement>(
       Source{Source::Location{12, 34}}, csl_2,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
+      create<ast::BlockStatement>(ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
+  switch_body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, switch_body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -383,35 +292,23 @@
   // switch (a) {
   //   default: { fallthrough; }
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
   ast::CaseSelectorList default_csl;
   auto* block_default = create<ast::BlockStatement>(
-      Source{},
+
       ast::StatementList{
           create<ast::FallthroughStatement>(Source{Source::Location{12, 34}}),
       });
   ast::CaseStatementList body;
-  body.push_back(
-      create<ast::CaseStatement>(Source{}, default_csl, block_default));
+  body.push_back(create<ast::CaseStatement>(default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -425,37 +322,24 @@
   //   default: {}
   //   case 5: {}
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
                                             default_csl, block_default));
   ast::CaseSelectorList case_csl;
-  case_csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
-  auto* block_case =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
-  body.push_back(create<ast::CaseStatement>(Source{}, case_csl, block_case));
+  case_csl.push_back(Literal(5));
+  auto* block_case = create<ast::BlockStatement>(ast::StatementList{});
+  body.push_back(create<ast::CaseStatement>(case_csl, block_case));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, body),
-                });
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, body),
+  });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error();
 }
@@ -467,35 +351,23 @@
   //   default: {}
   // }
 
-  ast::type::U32 u32;
-  ast::type::Alias my_int{mod()->RegisterSymbol("MyInt"), "MyInt", &u32};
+  ast::type::Alias my_int{mod->RegisterSymbol("MyInt"), "MyInt", ty.u32};
 
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &my_int,                   // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &u32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, &my_int, Expr(2u),
+                  ast::VariableDecorationList{});
 
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
+  auto* cond = Expr("a");
   ast::CaseSelectorList default_csl;
-  auto* block_default =
-      create<ast::BlockStatement>(Source{}, ast::StatementList{});
+  auto* block_default = create<ast::BlockStatement>(ast::StatementList{});
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
                                             default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::SwitchStatement>(Source{}, cond, body),
-                });
-  mod()->AddConstructedType(&my_int);
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::SwitchStatement>(cond, body),
+  });
+  mod->AddConstructedType(&my_int);
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error();
diff --git a/src/validator/validator_function_test.cc b/src/validator/validator_function_test.cc
index 94db436..5d2b246 100644
--- a/src/validator/validator_function_test.cc
+++ b/src/validator/validator_function_test.cc
@@ -38,100 +38,74 @@
 TEST_F(ValidateFunctionTest, VoidFunctionEndWithoutReturnStatement_Pass) {
   // [[stage(vertex)]]
   // fn func -> void { var a:i32 = 2; }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
   ast::VariableList params;
-  ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+  });
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &void_type, body,
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
+      params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_TRUE(v()->Validate(mod()));
+  EXPECT_TRUE(v()->Validate(mod));
 }
 
 TEST_F(ValidateFunctionTest,
        VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
   // [[stage(vertex)]]
   // fn func -> void {}
-  ast::type::Void void_type;
   ast::VariableList params;
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &void_type,
-      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
+      params, ty.void_, create<ast::BlockStatement>(ast::StatementList{}),
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_TRUE(v()->Validate(mod()));
+  EXPECT_TRUE(v()->Validate(mod));
 }
 
 TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatement_Fail) {
   // fn func -> int { var a:i32 = 2; }
 
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
   ast::VariableList params;
-  ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+  });
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &i32, body, ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
+      params, ty.i32, body, ast::FunctionDecorationList{});
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0002: non-void function must end with a return statement");
 }
 
 TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
   // fn func -> int {}
-  ast::type::Void void_type;
-  ast::type::I32 i32;
   ast::VariableList params;
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &i32, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
+      params, ty.i32, create<ast::BlockStatement>(ast::StatementList{}),
       ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0002: non-void function must end with a return statement");
 }
@@ -139,45 +113,39 @@
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_Pass) {
   // [[stage(vertex)]]
   // fn func -> void { return; }
-  ast::type::Void void_type;
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(),
+  });
   auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body,
+      mod->RegisterSymbol("func"), "func", params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
-  EXPECT_TRUE(td()->DetermineFunctions(mod()->functions())) << td()->error();
-  EXPECT_TRUE(v()->ValidateFunctions(mod()->functions())) << v()->error();
+  EXPECT_TRUE(td()->DetermineFunctions(mod->functions())) << td()->error();
+  EXPECT_TRUE(v()->ValidateFunctions(mod->functions())) << v()->error();
 }
 
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
   // fn func -> void { return 2; }
-  ast::type::Void void_type;
-  ast::type::I32 i32;
   ast::VariableList params;
-  auto* return_expr = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* return_expr = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(
-                        Source{Source::Location{12, 34}}, return_expr),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
+                                   return_expr),
+  });
 
-  auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
-                                     "func", params, &void_type, body,
-                                     ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+  auto* func =
+      create<ast::Function>(mod->RegisterSymbol("func"), "func", params,
+                            ty.void_, body, ast::FunctionDecorationList{});
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   // TODO(sarahM0): replace 000y with a rule number
   EXPECT_EQ(v()->error(),
             "12:34 v-000y: return statement type must match its function "
@@ -186,25 +154,21 @@
 
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
   // fn func -> f32 { return 2; }
-  ast::type::I32 i32;
-  ast::type::F32 f32;
   ast::VariableList params;
-  auto* return_expr = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* return_expr = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(
-                        Source{Source::Location{12, 34}}, return_expr),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
+                                   return_expr),
+  });
 
   auto* func =
-      create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
-                            params, &f32, body, ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+      create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.f32,
+                            body, ast::FunctionDecorationList{});
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   // TODO(sarahM0): replace 000y with a rule number
   EXPECT_EQ(v()->error(),
             "12:34 v-000y: return statement type must match its function "
@@ -214,127 +178,100 @@
 TEST_F(ValidateFunctionTest, FunctionNamesMustBeUnique_fail) {
   // fn func -> i32 { return 2; }
   // fn func -> i32 { return 2; }
-  ast::type::Void void_type;
-  ast::type::I32 i32;
 
   ast::VariableList params;
-  auto* return_expr = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* return_expr = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}, return_expr),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(return_expr),
+  });
   auto* func =
-      create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
-                            params, &i32, body, ast::FunctionDecorationList{});
+      create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.i32,
+                            body, ast::FunctionDecorationList{});
 
   ast::VariableList params_copy;
-  auto* return_expr_copy = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
-  auto* body_copy = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}, return_expr_copy),
-                });
+  auto* return_expr_copy = Expr(2);
+  auto* body_copy = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(return_expr_copy),
+  });
 
   auto* func_copy = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params_copy, &i32, body_copy, ast::FunctionDecorationList{});
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
+      params_copy, ty.i32, body_copy, ast::FunctionDecorationList{});
 
-  mod()->AddFunction(func);
-  mod()->AddFunction(func_copy);
+  mod->AddFunction(func);
+  mod->AddFunction(func_copy);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(), "12:34 v-0016: function names must be unique 'func'");
 }
 
 TEST_F(ValidateFunctionTest, RecursionIsNotAllowed_Fail) {
   // fn func() -> void {func(); return; }
-  ast::type::F32 f32;
-  ast::type::Void void_type;
   ast::ExpressionList call_params;
   auto* call_expr = create<ast::CallExpression>(
-      Source{Source::Location{12, 34}},
-      create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"),
-                                        "func"),
-      call_params);
+      Source{Source::Location{12, 34}}, Expr("func"), call_params);
   ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::CallStatement>(Source{}, call_expr),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
-                                      "func", params0, &f32, body0,
-                                      ast::FunctionDecorationList{});
-  mod()->AddFunction(func0);
+  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::CallStatement>(call_expr),
+      create<ast::ReturnStatement>(),
+  });
+  auto* func0 =
+      create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
+                            ty.f32, body0, ast::FunctionDecorationList{});
+  mod->AddFunction(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod())) << v()->error();
+  EXPECT_FALSE(v()->Validate(mod)) << v()->error();
   EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'");
 }
 
 TEST_F(ValidateFunctionTest, RecursionIsNotAllowedExpr_Fail) {
   // fn func() -> i32 {var a: i32 = func(); return 2; }
-  ast::type::I32 i32;
   ast::ExpressionList call_params;
   auto* call_expr = create<ast::CallExpression>(
-      Source{Source::Location{12, 34}},
-      create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol("func"),
-                                        "func"),
-      call_params);
-  auto* var =
-      create<ast::Variable>(Source{},                        // source
-                            "a",                             // name
-                            ast::StorageClass::kNone,        // storage_class
-                            &i32,                            // type
-                            false,                           // is_const
-                            call_expr,                       // constructor
-                            ast::VariableDecorationList{});  // decorations
+      Source{Source::Location{12, 34}}, Expr("func"), call_params);
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, call_expr,
+                  ast::VariableDecorationList{});
 
   ast::VariableList params0;
-  auto* return_expr = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* return_expr = Expr(2);
 
-  auto* body0 = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}, return_expr),
-                });
+  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::ReturnStatement>(return_expr),
+  });
 
-  auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
-                                      "func", params0, &i32, body0,
-                                      ast::FunctionDecorationList{});
-  mod()->AddFunction(func0);
+  auto* func0 =
+      create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
+                            ty.i32, body0, ast::FunctionDecorationList{});
+  mod->AddFunction(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod())) << v()->error();
+  EXPECT_FALSE(v()->Validate(mod)) << v()->error();
   EXPECT_EQ(v()->error(), "12:34 v-0004: recursion is not allowed: 'func'");
 }
 
 TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) {
   // [[stage(vertex)]]
   // fn vtx_main() -> i32 { return 0; }
-  ast::type::I32 i32;
   ast::VariableList params;
-  auto* return_expr = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 0));
+  auto* return_expr = Expr(0);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}, return_expr),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(return_expr),
+  });
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_main"),
-      "vtx_main", params, &i32, body,
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_main"),
+      "vtx_main", params, ty.i32, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
 
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0024: Entry point function must return void: 'vtx_main'");
 }
@@ -342,31 +279,22 @@
 TEST_F(ValidateFunctionTest, Function_WithPipelineStage_WithParams_Fail) {
   // [[stage(vertex)]]
   // fn vtx_func(a : i32) -> void { return; }
-  ast::type::I32 i32;
-  ast::type::Void void_type;
   ast::VariableList params;
-  params.push_back(
-      create<ast::Variable>(Source{},                         // source
-                            "a",                              // name
-                            ast::StorageClass::kNone,         // storage_class
-                            &i32,                             // type
-                            false,                            // is_const
-                            nullptr,                          // constructor
-                            ast::VariableDecorationList{}));  // decorations
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  params.push_back(Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
+                       ast::VariableDecorationList{}));
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(),
+  });
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_func"),
-      "vtx_func", params, &void_type, body,
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_func"),
+      "vtx_func", params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
 
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0023: Entry point function must accept no parameters: "
             "'vtx_func'");
@@ -376,23 +304,21 @@
   // [[stage(fragment)]]
   // [[stage(vertex)]]
   // fn main() -> void { return; }
-  ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(),
+  });
   auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("main"), "main",
-      params, &void_type, body,
+      Source{Source::Location{12, 34}}, mod->RegisterSymbol("main"), "main",
+      params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
 
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(
       v()->error(),
       "12:34 v-0020: only one stage decoration permitted per entry point");
@@ -401,39 +327,34 @@
 TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Pass) {
   // [[stage(vertex)]]
   // fn vtx_func() -> void { return; }
-  ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(),
+  });
   auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
-      &void_type, body,
+      mod->RegisterSymbol("vtx_func"), "vtx_func", params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_TRUE(v()->Validate(mod())) << v()->error();
+  EXPECT_TRUE(v()->Validate(mod)) << v()->error();
 }
 
 TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Fail) {
   // fn vtx_func() -> void { return; }
-  ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
-      &void_type, body, ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::ReturnStatement>(),
+  });
+  auto* func =
+      create<ast::Function>(mod->RegisterSymbol("vtx_func"), "vtx_func", params,
+                            ty.void_, body, ast::FunctionDecorationList{});
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "v-0003: At least one of vertex, fragment or compute shader must "
             "be present");
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index e617607..7a19bb5 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -62,13 +62,11 @@
 
 TEST_F(ValidatorTest, DISABLED_AssignToScalar_Fail) {
   // 1 = my_var;
-  ast::type::I32 i32;
 
-  auto* lhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 1));
-  auto* rhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("my_var"), "my_var");
-  ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs);
+  auto* lhs = Expr(1);
+  auto* rhs = Expr("my_var");
+  SetSource(Source{Source::Location{12, 34}});
+  create<ast::AssignmentStatement>(lhs, rhs);
 
   // TODO(sarahM0): Invalidate assignment to scalar.
   ASSERT_TRUE(v()->has_error());
@@ -78,14 +76,11 @@
 
 TEST_F(ValidatorTest, UsingUndefinedVariable_Fail) {
   // b = 2;
-  ast::type::I32 i32;
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("b"), "b");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
-  auto* assign = create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs);
+  SetSource(Source{Source::Location{12, 34}});
+  auto* lhs = Expr("b");
+  auto* rhs = Expr(2);
+  auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
   EXPECT_FALSE(td()->DetermineResultType(assign));
   EXPECT_EQ(td()->error(),
@@ -96,18 +91,14 @@
   // {
   //  b = 2;
   // }
-  ast::type::I32 i32;
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("b"), "b");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  SetSource(Source{Source::Location{12, 34}});
+  auto* lhs = Expr("b");
+  auto* rhs = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::AssignmentStatement>(lhs, rhs),
+  });
 
   EXPECT_FALSE(td()->DetermineStatements(body));
   EXPECT_EQ(td()->error(),
@@ -117,29 +108,19 @@
 TEST_F(ValidatorTest, AssignCompatibleTypes_Pass) {
   // var a :i32 = 2;
   // a = 2
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2);
 
-  ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs);
+  auto* assign = create<ast::AssignmentStatement>(
+      Source{Source::Location{12, 34}}, lhs, rhs);
   td()->RegisterVariableForTesting(var);
-  EXPECT_TRUE(td()->DetermineResultType(&assign)) << td()->error();
+  EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
   ASSERT_NE(rhs->result_type(), nullptr);
-  EXPECT_TRUE(v()->ValidateResultTypes(&assign));
+  EXPECT_TRUE(v()->ValidateResultTypes(assign));
 }
 
 TEST_F(ValidatorTest, AssignIncompatibleTypes_Fail) {
@@ -147,32 +128,21 @@
   //  var a :i32 = 2;
   //  a = 2.3;
   // }
-  ast::type::F32 f32;
-  ast::type::I32 i32;
 
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2.3f);
 
-  ast::AssignmentStatement assign(Source{Source::Location{12, 34}}, lhs, rhs);
+  auto* assign = create<ast::AssignmentStatement>(
+      Source{Source::Location{12, 34}}, lhs, rhs);
   td()->RegisterVariableForTesting(var);
-  EXPECT_TRUE(td()->DetermineResultType(&assign)) << td()->error();
+  EXPECT_TRUE(td()->DetermineResultType(assign)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
   ASSERT_NE(rhs->result_type(), nullptr);
 
-  EXPECT_FALSE(v()->ValidateResultTypes(&assign));
+  EXPECT_FALSE(v()->ValidateResultTypes(assign));
   ASSERT_TRUE(v()->has_error());
   // TODO(sarahM0): figure out what should be the error number.
   EXPECT_EQ(v()->error(),
@@ -184,29 +154,17 @@
   //  var a :i32 = 2;
   //  a = 2
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -220,36 +178,24 @@
   //  var a :i32 = 2;
   //  a = 2.3;
   // }
-  ast::type::F32 f32;
-  ast::type::I32 i32;
 
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  ast::BlockStatement block(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2.3f);
 
-  EXPECT_TRUE(td()->DetermineStatements(&block)) << td()->error();
+  auto* block = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
+
+  EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
   ASSERT_NE(rhs->result_type(), nullptr);
 
-  EXPECT_FALSE(v()->ValidateStatements(&block));
+  EXPECT_FALSE(v()->ValidateStatements(block));
   ASSERT_TRUE(v()->has_error());
   // TODO(sarahM0): figure out what should be the error number.
   EXPECT_EQ(v()->error(),
@@ -258,49 +204,31 @@
 
 TEST_F(ValidatorTest, GlobalVariableWithStorageClass_Pass) {
   // var<in> gloabl_var: f32;
-  ast::type::F32 f32;
-  mod()->AddGlobalVariable(
-      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
-                            "global_var",                      // name
-                            ast::StorageClass::kInput,         // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{}));   // decorations
-  EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables()))
+  mod->AddGlobalVariable(Var(Source{Source::Location{12, 34}}, "global_var",
+                             ast::StorageClass::kInput, ty.f32, nullptr,
+                             ast::VariableDecorationList{}));
+  EXPECT_TRUE(v()->ValidateGlobalVariables(mod->global_variables()))
       << v()->error();
 }
 
 TEST_F(ValidatorTest, GlobalVariableNoStorageClass_Fail) {
   // var gloabl_var: f32;
-  ast::type::F32 f32;
-  mod()->AddGlobalVariable(
-      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
-                            "global_var",                      // name
-                            ast::StorageClass::kNone,          // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{}));   // decorations
+  mod->AddGlobalVariable(Var(Source{Source::Location{12, 34}}, "global_var",
+                             ast::StorageClass::kNone, ty.f32, nullptr,
+                             ast::VariableDecorationList{}));
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0022: global variables must have a storage class");
 }
 
 TEST_F(ValidatorTest, GlobalConstantWithStorageClass_Fail) {
   // const<in> gloabl_var: f32;
-  ast::type::F32 f32;
-  mod()->AddGlobalVariable(
-      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
-                            "global_var",                      // name
-                            ast::StorageClass::kInput,         // storage_class
-                            &f32,                              // type
-                            true,                              // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{}));   // decorations
+  mod->AddGlobalVariable(Const(Source{Source::Location{12, 34}}, "global_var",
+                               ast::StorageClass::kInput, ty.f32, nullptr,
+                               ast::VariableDecorationList{}));
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(
       v()->error(),
       "12:34 v-global01: global constants shouldn't have a storage class");
@@ -308,17 +236,11 @@
 
 TEST_F(ValidatorTest, GlobalConstNoStorageClass_Pass) {
   // const gloabl_var: f32;
-  ast::type::F32 f32;
-  mod()->AddGlobalVariable(
-      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
-                            "global_var",                      // name
-                            ast::StorageClass::kNone,          // storage_class
-                            &f32,                              // type
-                            true,                              // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{}));   // decorations
+  mod->AddGlobalVariable(Const(Source{Source::Location{12, 34}}, "global_var",
+                               ast::StorageClass::kNone, ty.f32, nullptr,
+                               ast::VariableDecorationList{}));
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod())) << v()->error();
+  EXPECT_FALSE(v()->Validate(mod)) << v()->error();
 }
 
 TEST_F(ValidatorTest, UsingUndefinedVariableGlobalVariable_Fail) {
@@ -326,37 +248,25 @@
   // fn my_func() -> f32 {
   //   not_global_var = 3.14f;
   // }
-  ast::type::F32 f32;
-  mod()->AddGlobalVariable(create<ast::Variable>(
-      Source{},                     // source
-      "global_var",                 // name
-      ast::StorageClass::kPrivate,  // storage_class
-      &f32,                         // type
-      false,                        // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.1)),  // constructor
-      ast::VariableDecorationList{}));                      // decorations
+  mod->AddGlobalVariable(Var("global_var", ast::StorageClass::kPrivate, ty.f32,
+                             Expr(2.1f), ast::VariableDecorationList{}));
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("not_global_var"),
-      "not_global_var");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
+  SetSource(Source{Source::Location{12, 34}});
+  auto* lhs = Expr("not_global_var");
+  auto* rhs = Expr(3.14f);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
-  auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
-                                     "my_func", params, &f32, body,
-                                     ast::FunctionDecorationList{});
-  mod()->AddFunction(func);
+  auto* func =
+      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
+                            ty.f32, body, ast::FunctionDecorationList{});
+  mod->AddFunction(func);
 
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(), "12:34 v-0006: 'not_global_var' is not declared");
 }
 
@@ -366,44 +276,31 @@
   //   global_var = 3.14;
   //   return;
   // }
-  ast::type::F32 f32;
-  ast::type::Void void_type;
 
-  mod()->AddGlobalVariable(create<ast::Variable>(
-      Source{},                     // source
-      "global_var",                 // name
-      ast::StorageClass::kPrivate,  // storage_class
-      &f32,                         // type
-      false,                        // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.1)),  // constructor
-      ast::VariableDecorationList{}));                      // decorations
+  mod->AddGlobalVariable(Var("global_var", ast::StorageClass::kPrivate, ty.f32,
+                             Expr(2.1f), ast::VariableDecorationList{}));
 
   auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("global_var"), "global_var");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
+      mod->RegisterSymbol("global_var"), "global_var");
+  auto* rhs = Expr(3.14f);
 
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+      create<ast::ReturnStatement>(),
+  });
 
   auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("my_func"), "my_func", params, &void_type,
-      body,
+      mod->RegisterSymbol("my_func"), "my_func", params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_TRUE(v()->Validate(mod())) << v()->error();
+  EXPECT_TRUE(v()->Validate(mod)) << v()->error();
 }
 
 TEST_F(ValidatorTest, UsingUndefinedVariableInnerScope_Fail) {
@@ -411,38 +308,24 @@
   //   if (true) { var a : f32 = 2.0; }
   //   a = 3.14;
   // }
-  ast::type::F32 f32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                  ast::VariableDecorationList{});
 
   ast::type::Bool bool_type;
-  auto* cond = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                });
+  auto* cond = Expr(true);
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+  });
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
+  SetSource(Source{Source::Location{12, 34}});
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(3.14f);
 
-  auto* outer_body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::IfStatement>(Source{}, cond, body,
-                                             ast::ElseStatementList{}),
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -456,38 +339,24 @@
   //   var a : f32 = 2.0;
   //   if (true) { a = 3.14; }
   // }
-  ast::type::F32 f32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                  ast::VariableDecorationList{});
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
+  SetSource(Source{Source::Location{12, 34}});
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(3.14f);
 
   ast::type::Bool bool_type;
-  auto* cond = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* cond = Expr(true);
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
-  auto* outer_body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::IfStatement>(Source{}, cond, body,
-                                             ast::ElseStatementList{}),
-                });
+  auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -498,66 +367,32 @@
 TEST_F(ValidatorTest, GlobalVariableUnique_Pass) {
   // var global_var0 : f32 = 0.1;
   // var global_var1 : i32 = 0;
-  ast::type::F32 f32;
-  ast::type::I32 i32;
-  auto* var0 = create<ast::Variable>(
-      Source{},                     // source
-      "global_var0",                // name
-      ast::StorageClass::kPrivate,  // storage_class
-      &f32,                         // type
-      false,                        // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 0.1)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
-  mod()->AddGlobalVariable(var0);
+  auto* var0 = Var("global_var0", ast::StorageClass::kPrivate, ty.f32,
+                   Expr(0.1f), ast::VariableDecorationList{});
+  mod->AddGlobalVariable(var0);
 
-  auto* var1 = create<ast::Variable>(
-      Source{Source::Location{12, 34}},  // source
-      "global_var1",                     // name
-      ast::StorageClass::kPrivate,       // storage_class
-      &f32,                              // type
-      false,                             // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 0)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
-  mod()->AddGlobalVariable(var1);
+  auto* var1 = Var(Source{Source::Location{12, 34}}, "global_var1",
+                   ast::StorageClass::kPrivate, ty.f32, Expr(0),
+                   ast::VariableDecorationList{});
+  mod->AddGlobalVariable(var1);
 
-  EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables()))
+  EXPECT_TRUE(v()->ValidateGlobalVariables(mod->global_variables()))
       << v()->error();
 }
 
 TEST_F(ValidatorTest, GlobalVariableNotUnique_Fail) {
   // var global_var : f32 = 0.1;
   // var global_var : i32 = 0;
-  ast::type::F32 f32;
-  ast::type::I32 i32;
-  auto* var0 = create<ast::Variable>(
-      Source{},                     // source
-      "global_var",                 // name
-      ast::StorageClass::kPrivate,  // storage_class
-      &f32,                         // type
-      false,                        // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 0.1)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
-  mod()->AddGlobalVariable(var0);
+  auto* var0 = Var("global_var", ast::StorageClass::kPrivate, ty.f32,
+                   Expr(0.1f), ast::VariableDecorationList{});
+  mod->AddGlobalVariable(var0);
 
-  auto* var1 = create<ast::Variable>(
-      Source{Source::Location{12, 34}},  // source
-      "global_var",                      // name
-      ast::StorageClass::kPrivate,       // storage_class
-      &f32,                              // type
-      false,                             // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 0)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
-  mod()->AddGlobalVariable(var1);
+  auto* var1 = Var(Source{Source::Location{12, 34}}, "global_var",
+                   ast::StorageClass::kPrivate, ty.i32, Expr(0),
+                   ast::VariableDecorationList{});
+  mod->AddGlobalVariable(var1);
 
-  EXPECT_FALSE(v()->ValidateGlobalVariables(mod()->global_variables()));
+  EXPECT_FALSE(v()->ValidateGlobalVariables(mod->global_variables()));
   EXPECT_EQ(v()->error(),
             "12:34 v-0011: redeclared global identifier 'global_var'");
 }
@@ -567,29 +402,17 @@
   //  const a :i32 = 2;
   //  a = 2
   // }
-  ast::type::I32 i32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      true,                      // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Const("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                    ast::VariableDecorationList{});
 
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -606,46 +429,26 @@
   //   return 0;
   // }
 
-  ast::type::Void void_type;
-  ast::type::F32 f32;
-  auto* global_var = create<ast::Variable>(
-      Source{},                     // source
-      "a",                          // name
-      ast::StorageClass::kPrivate,  // storage_class
-      &f32,                         // type
-      false,                        // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.1)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
-  mod()->AddGlobalVariable(global_var);
+  auto* global_var = Var("a", ast::StorageClass::kPrivate, ty.f32, Expr(2.1f),
+                         ast::VariableDecorationList{});
+  mod->AddGlobalVariable(global_var);
 
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                  ast::VariableDecorationList{});
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
+  });
 
-  auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
-                                     "my_func", params, &void_type, body,
-                                     ast::FunctionDecorationList{});
+  auto* func =
+      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
+                            ty.void_, body, ast::FunctionDecorationList{});
 
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod())) << v()->error();
+  EXPECT_FALSE(v()->Validate(mod)) << v()->error();
   EXPECT_EQ(v()->error(), "12:34 v-0013: redeclared identifier 'a'");
 }
 
@@ -654,48 +457,28 @@
   //  var a :i32 = 2;
   //  var a :f21 = 2.0;
   // }
-  ast::type::Void void_type;
-  ast::type::I32 i32;
-  ast::type::F32 f32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &i32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::SintLiteral>(Source{}, &i32, 2)),  // constructor
-      ast::VariableDecorationList{});                    // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
+                  ast::VariableDecorationList{});
 
-  auto* var_a_float = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 0.1)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(0.1f),
+                          ast::VariableDecorationList{});
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var_a_float),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
+                                         var_a_float),
+  });
 
-  auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
-                                     "my_func", params, &void_type, body,
-                                     ast::FunctionDecorationList{});
+  auto* func =
+      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
+                            ty.void_, body, ast::FunctionDecorationList{});
 
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_TRUE(td()->DetermineFunction(func)) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(), "12:34 v-0014: redeclared identifier 'a'");
 }
 
@@ -704,44 +487,23 @@
   // if (true) { var a : f32 = 2.0; }
   // var a : f32 = 3.14;
   // }
-  ast::type::F32 f32;
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                  ast::VariableDecorationList{});
 
   ast::type::Bool bool_type;
-  auto* cond = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                });
+  auto* cond = Expr(true);
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+  });
 
-  auto* var_a_float = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 3.14)),  // constructor
-      ast::VariableDecorationList{});                        // decorations
+  auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.1f),
+                          ast::VariableDecorationList{});
 
-  auto* outer_body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::IfStatement>(Source{}, cond, body,
-                                             ast::ElseStatementList{}),
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var_a_float),
-                });
+  auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
+                                         var_a_float),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   EXPECT_TRUE(v()->ValidateStatements(outer_body)) << v()->error();
@@ -754,44 +516,22 @@
   // var a : f32 = 3.14;
   // if (true) { var a : f32 = 2.0; }
   // }
-  ast::type::F32 f32;
-  auto* var_a_float = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 3.14)),  // constructor
-      ast::VariableDecorationList{});                        // decorations
+  auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(3.1f),
+                          ast::VariableDecorationList{});
 
-  auto* var = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                  ast::VariableDecorationList{});
 
   ast::type::Bool bool_type;
-  auto* cond = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var),
-                });
+  auto* cond = Expr(true);
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
+  });
 
-  auto* outer_body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var_a_float),
-                    create<ast::IfStatement>(Source{}, cond, body,
-                                             ast::ElseStatementList{}),
-                });
+  auto* outer_body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var_a_float),
+      create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(outer_body));
@@ -801,61 +541,40 @@
 TEST_F(ValidatorTest, RedeclaredIdentifierDifferentFunctions_Pass) {
   // func0 { var a : f32 = 2.0; return; }
   // func1 { var a : f32 = 3.0; return; }
-  ast::type::F32 f32;
-  ast::type::Void void_type;
-  auto* var0 = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &f32,                      // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var0 = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
+                   ast::VariableDecorationList{});
 
-  auto* var1 = create<ast::Variable>(
-      Source{},                  // source
-      "a",                       // name
-      ast::StorageClass::kNone,  // storage_class
-      &void_type,                // type
-      false,                     // is_const
-      create<ast::ScalarConstructorExpression>(
-          Source{},
-          create<ast::FloatLiteral>(Source{}, &f32, 1.0)),  // constructor
-      ast::VariableDecorationList{});                       // decorations
+  auto* var1 = Var("a", ast::StorageClass::kNone, ty.void_, Expr(1.0f),
+                   ast::VariableDecorationList{});
 
   ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var0),
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
+                                         var0),
+      create<ast::ReturnStatement>(),
+  });
 
-  auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func0"),
-                                      "func0", params0, &void_type, body0,
-                                      ast::FunctionDecorationList{});
+  auto* func0 =
+      create<ast::Function>(mod->RegisterSymbol("func0"), "func0", params0,
+                            ty.void_, body0, ast::FunctionDecorationList{});
 
   ast::VariableList params1;
-  auto* body1 = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{13, 34}}, var1),
-                    create<ast::ReturnStatement>(Source{}),
-                });
+  auto* body1 = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(Source{Source::Location{13, 34}},
+                                         var1),
+      create<ast::ReturnStatement>(),
+  });
   auto* func1 = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("func1"), "func1", params1, &void_type,
-      body1,
+      mod->RegisterSymbol("func1"), "func1", params1, ty.void_, body1,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
 
-  mod()->AddFunction(func0);
-  mod()->AddFunction(func1);
+  mod->AddFunction(func0);
+  mod->AddFunction(func1);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_TRUE(v()->Validate(mod())) << v()->error();
+  EXPECT_TRUE(v()->Validate(mod)) << v()->error();
 }
 
 TEST_F(ValidatorTest, VariableDeclNoConstructor_Pass) {
@@ -863,28 +582,18 @@
   // var a :i32;
   // a = 2;
   // }
-  ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{},                        // source
-                            "a",                             // name
-                            ast::StorageClass::kNone,        // storage_class
-                            &i32,                            // type
-                            false,                           // is_const
-                            nullptr,                         // constructor
-                            ast::VariableDecorationList{});  // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
+                  ast::VariableDecorationList{});
 
   td()->RegisterVariableForTesting(var);
-  auto* lhs = create<ast::IdentifierExpression>(
-      Source{}, mod()->RegisterSymbol("a"), "a");
-  auto* rhs = create<ast::ScalarConstructorExpression>(
-      Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* lhs = Expr("a");
+  auto* rhs = Expr(2);
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::AssignmentStatement>(
-                        Source{Source::Location{12, 34}}, lhs, rhs),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(var),
+      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
+                                       rhs),
+  });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
diff --git a/src/validator/validator_test_helper.cc b/src/validator/validator_test_helper.cc
index eae9e96..656b6f6 100644
--- a/src/validator/validator_test_helper.cc
+++ b/src/validator/validator_test_helper.cc
@@ -19,7 +19,7 @@
 namespace tint {
 
 ValidatorTestHelper::ValidatorTestHelper() {
-  td_ = std::make_unique<TypeDeterminer>(&mod_);
+  td_ = std::make_unique<TypeDeterminer>(mod);
   v_ = std::make_unique<ValidatorImpl>();
 }
 
diff --git a/src/validator/validator_test_helper.h b/src/validator/validator_test_helper.h
index e5f3cfc..bc15b32 100644
--- a/src/validator/validator_test_helper.h
+++ b/src/validator/validator_test_helper.h
@@ -18,6 +18,7 @@
 #include <memory>
 #include <utility>
 
+#include "src/ast/builder.h"
 #include "src/ast/type/void_type.h"
 #include "src/type_determiner.h"
 #include "src/validator/validator_impl.h"
@@ -25,11 +26,11 @@
 namespace tint {
 
 /// A helper for testing validation
-class ValidatorTestHelper {
+class ValidatorTestHelper : public ast::BuilderWithModule {
  public:
   /// Constructor
   ValidatorTestHelper();
-  ~ValidatorTestHelper();
+  ~ValidatorTestHelper() override;
 
   /// A handle to validator
   /// @returns a pointer to the validator
@@ -37,24 +38,10 @@
   /// A handle to type_determiner
   /// @returns a pointer to the type_determiner object
   TypeDeterminer* td() const { return td_.get(); }
-  /// A handle to the created module
-  /// @return a pointer to the test module
-  ast::Module* mod() { return &mod_; }
-
-  /// Creates a new `ast::Node` owned by the Module. When the Module is
-  /// destructed, the `ast::Node` will also be destructed.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  T* create(ARGS&&... args) {
-    return mod_.create<T>(std::forward<ARGS>(args)...);
-  }
 
  private:
   std::unique_ptr<ValidatorImpl> v_;
-  ast::Module mod_;
   std::unique_ptr<TypeDeterminer> td_;
-  ast::type::Void void_type_;
 };
 
 }  // namespace tint
diff --git a/src/validator/validator_type_test.cc b/src/validator/validator_type_test.cc
index 46aaa96..aceeed0 100644
--- a/src/validator/validator_type_test.cc
+++ b/src/validator/validator_type_test.cc
@@ -42,25 +42,23 @@
   //   rt: array<f32>;
   // };
 
-  ast::type::F32 f32;
-  ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
   ast::StructMemberList members;
   {
     ast::StructMemberDecorationList deco;
-    members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco));
+    members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
   }
   {
     ast::StructMemberDecorationList deco;
     members.push_back(create<ast::StructMember>(
-        Source{Source::Location{12, 34}}, "rt", &arr, deco));
+        Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
   }
   ast::StructDecorationList decos;
-  decos.push_back(create<ast::StructBlockDecoration>(Source{}));
-  auto* st = create<ast::Struct>(Source{}, members, decos);
-  ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st);
+  decos.push_back(create<ast::StructBlockDecoration>());
+  auto* st = create<ast::Struct>(members, decos);
+  ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
 
-  mod()->AddConstructedType(&struct_type);
-  EXPECT_TRUE(v()->ValidateConstructedTypes(mod()->constructed_types()));
+  mod->AddConstructedType(&struct_type);
+  EXPECT_TRUE(v()->ValidateConstructedTypes(mod->constructed_types()));
 }
 
 TEST_F(ValidatorTypeTest, RuntimeArrayIsLastNoBlock_Fail) {
@@ -69,24 +67,22 @@
   //   rt: array<f32>;
   // };
 
-  ast::type::F32 f32;
-  ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
   ast::StructMemberList members;
   {
     ast::StructMemberDecorationList deco;
-    members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco));
+    members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
   }
   {
     ast::StructMemberDecorationList deco;
     members.push_back(create<ast::StructMember>(
-        Source{Source::Location{12, 34}}, "rt", &arr, deco));
+        Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
   }
   ast::StructDecorationList decos;
-  auto* st = create<ast::Struct>(Source{}, members, decos);
-  ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st);
+  auto* st = create<ast::Struct>(members, decos);
+  ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
 
-  mod()->AddConstructedType(&struct_type);
-  EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types()));
+  mod->AddConstructedType(&struct_type);
+  EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
   EXPECT_EQ(v()->error(),
             "12:34 v-0031: a struct containing a runtime-sized array must be "
             "in the 'storage' storage class: 'Foo'");
@@ -99,25 +95,23 @@
   //   vf: f32;
   // };
 
-  ast::type::F32 f32;
-  ast::type::Array arr(&f32, 0, ast::ArrayDecorationList{});
   ast::StructMemberList members;
   {
     ast::StructMemberDecorationList deco;
     members.push_back(create<ast::StructMember>(
-        Source{Source::Location{12, 34}}, "rt", &arr, deco));
+        Source{Source::Location{12, 34}}, "rt", ty.array<f32>(), deco));
   }
   {
     ast::StructMemberDecorationList deco;
-    members.push_back(create<ast::StructMember>(Source{}, "vf", &f32, deco));
+    members.push_back(create<ast::StructMember>("vf", ty.f32, deco));
   }
   ast::StructDecorationList decos;
-  decos.push_back(create<ast::StructBlockDecoration>(Source{}));
-  auto* st = create<ast::Struct>(Source{}, members, decos);
-  ast::type::Struct struct_type(mod()->RegisterSymbol("Foo"), "Foo", st);
+  decos.push_back(create<ast::StructBlockDecoration>());
+  auto* st = create<ast::Struct>(members, decos);
+  ast::type::Struct struct_type(mod->RegisterSymbol("Foo"), "Foo", st);
 
-  mod()->AddConstructedType(&struct_type);
-  EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types()));
+  mod->AddConstructedType(&struct_type);
+  EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
   EXPECT_EQ(v()->error(),
             "12:34 v-0015: runtime arrays may only appear as the last member "
             "of a struct: 'rt'");
@@ -131,9 +125,8 @@
   //  a: u32;
   //}
 
-  ast::type::F32 u32;
-  ast::type::Array array(&u32, 0, ast::ArrayDecorationList{});
-  ast::type::Alias alias{mod()->RegisterSymbol("RTArr"), "RTArr", &array};
+  ast::type::Alias alias{mod->RegisterSymbol("RTArr"), "RTArr",
+                         ty.array<u32>()};
 
   ast::StructMemberList members;
   {
@@ -143,15 +136,15 @@
   }
   {
     ast::StructMemberDecorationList deco;
-    members.push_back(create<ast::StructMember>(Source{}, "a", &u32, deco));
+    members.push_back(create<ast::StructMember>("a", ty.u32, deco));
   }
 
   ast::StructDecorationList decos;
-  decos.push_back(create<ast::StructBlockDecoration>(Source{}));
-  auto* st = create<ast::Struct>(Source{}, members, decos);
-  ast::type::Struct struct_type(mod()->RegisterSymbol("s"), "s", st);
-  mod()->AddConstructedType(&struct_type);
-  EXPECT_FALSE(v()->ValidateConstructedTypes(mod()->constructed_types()));
+  decos.push_back(create<ast::StructBlockDecoration>());
+  auto* st = create<ast::Struct>(members, decos);
+  ast::type::Struct struct_type(mod->RegisterSymbol("s"), "s", st);
+  mod->AddConstructedType(&struct_type);
+  EXPECT_FALSE(v()->ValidateConstructedTypes(mod->constructed_types()));
   EXPECT_EQ(v()->error(),
             "12:34 v-0015: runtime arrays may only appear as the last member "
             "of a struct: 'b'");
@@ -165,14 +158,13 @@
   //  b: RTArr;
   //}
 
-  ast::type::F32 u32;
-  ast::type::Array array(&u32, 0, ast::ArrayDecorationList{});
-  ast::type::Alias alias{mod()->RegisterSymbol("RTArr"), "RTArr", &array};
+  ast::type::Alias alias{mod->RegisterSymbol("RTArr"), "RTArr",
+                         ty.array<u32>()};
 
   ast::StructMemberList members;
   {
     ast::StructMemberDecorationList deco;
-    members.push_back(create<ast::StructMember>(Source{}, "a", &u32, deco));
+    members.push_back(create<ast::StructMember>("a", ty.u32, deco));
   }
   {
     ast::StructMemberDecorationList deco;
@@ -180,43 +172,31 @@
         Source{Source::Location{12, 34}}, "b", &alias, deco));
   }
   ast::StructDecorationList decos;
-  decos.push_back(create<ast::StructBlockDecoration>(Source{}));
-  auto* st = create<ast::Struct>(Source{}, members, decos);
-  ast::type::Struct struct_type(mod()->RegisterSymbol("s"), "s", st);
-  mod()->AddConstructedType(&struct_type);
-  EXPECT_TRUE(v()->ValidateConstructedTypes(mod()->constructed_types()));
+  decos.push_back(create<ast::StructBlockDecoration>());
+  auto* st = create<ast::Struct>(members, decos);
+  ast::type::Struct struct_type(mod->RegisterSymbol("s"), "s", st);
+  mod->AddConstructedType(&struct_type);
+  EXPECT_TRUE(v()->ValidateConstructedTypes(mod->constructed_types()));
 }
 
 TEST_F(ValidatorTypeTest, RuntimeArrayInFunction_Fail) {
   /// [[stage(vertex)]]
   // fn func -> void { var a : array<i32>; }
-  ast::type::I32 i32;
-  ast::type::Array array(&i32, 0, ast::ArrayDecorationList{});
 
-  auto* var =
-      create<ast::Variable>(Source{},                        // source
-                            "a",                             // name
-                            ast::StorageClass::kNone,        // storage_class
-                            &array,                          // type
-                            false,                           // is_const
-                            nullptr,                         // constructor
-                            ast::VariableDecorationList{});  // decorations
+  auto* var = Var("a", ast::StorageClass::kNone, ty.array<i32>());
   ast::VariableList params;
-  ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(
-                        Source{Source::Location{12, 34}}, var),
-                });
+  auto* body = create<ast::BlockStatement>(ast::StatementList{
+      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
+  });
   auto* func = create<ast::Function>(
-      Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body,
+      mod->RegisterSymbol("func"), "func", params, ty.void_, body,
       ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
+          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
-  mod()->AddFunction(func);
+  mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
-  EXPECT_FALSE(v()->Validate(mod()));
+  EXPECT_FALSE(v()->Validate(mod));
   EXPECT_EQ(v()->error(),
             "12:34 v-0015: runtime arrays may only appear as the last member "
             "of a struct: 'a'");