test: Add Build() method for tests using ast::Builder

This separates out the usage of the built module from the construction of the module.

Previously, we'd happily interleave generator testing with module construction statements. Once the AST / Program is made immutable, this will no longer be possible.

Bug: tint:390
Change-Id: Ib4538228e93ca816f5bb796d024f021116609213
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/38360
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/writer/hlsl/generator_impl_alias_type_test.cc b/src/writer/hlsl/generator_impl_alias_type_test.cc
index e04d641..04a4f8b 100644
--- a/src/writer/hlsl/generator_impl_alias_type_test.cc
+++ b/src/writer/hlsl/generator_impl_alias_type_test.cc
@@ -29,6 +29,8 @@
 TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_F32) {
   auto* alias = ty.alias("a", ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructedType(out, alias)) << gen.error();
   EXPECT_EQ(result(), R"(typedef float a;
 )");
@@ -37,6 +39,8 @@
 TEST_F(HlslGeneratorImplTest_Alias, EmitAlias_NameCollision) {
   auto* alias = ty.alias("float", ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructedType(out, alias)) << gen.error();
   EXPECT_EQ(result(), R"(typedef float float_tint_0;
 )");
@@ -51,6 +55,8 @@
   auto* s = ty.struct_("A", str);
   auto* alias = ty.alias("B", s);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructedType(out, alias)) << gen.error();
   EXPECT_EQ(result(), R"(struct B {
   float a;
diff --git a/src/writer/hlsl/generator_impl_array_accessor_test.cc b/src/writer/hlsl/generator_impl_array_accessor_test.cc
index cb65569..79cf085 100644
--- a/src/writer/hlsl/generator_impl_array_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_array_accessor_test.cc
@@ -32,6 +32,8 @@
 TEST_F(HlslGeneratorImplTest_Expression, EmitExpression_ArrayAccessor) {
   auto* expr = IndexAccessor("ary", 5);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "ary[5]");
 }
@@ -39,6 +41,8 @@
 TEST_F(HlslGeneratorImplTest_Expression, EmitArrayAccessor) {
   auto* expr = IndexAccessor("ary", "idx");
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "ary[idx]");
 }
diff --git a/src/writer/hlsl/generator_impl_assign_test.cc b/src/writer/hlsl/generator_impl_assign_test.cc
index 549ce5e..c44681c 100644
--- a/src/writer/hlsl/generator_impl_assign_test.cc
+++ b/src/writer/hlsl/generator_impl_assign_test.cc
@@ -32,6 +32,8 @@
   auto* rhs = Expr("rhs");
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_binary_test.cc b/src/writer/hlsl/generator_impl_binary_test.cc
index 3240c10..1786684 100644
--- a/src/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/writer/hlsl/generator_impl_binary_test.cc
@@ -72,6 +72,9 @@
   auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
@@ -90,6 +93,9 @@
   auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
@@ -108,6 +114,9 @@
   auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
@@ -140,6 +149,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "(float3(1.0f, 1.0f, 1.0f) * "
@@ -154,6 +166,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "(1.0f * float3(1.0f, 1.0f, "
@@ -171,6 +186,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "(mat * 1.0f)");
 }
@@ -186,6 +204,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "(1.0f * mat)");
 }
@@ -201,6 +222,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "mul(mat, float3(1.0f, 1.0f, 1.0f))");
 }
@@ -216,6 +240,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "mul(float3(1.0f, 1.0f, 1.0f), mat)");
 }
@@ -231,6 +258,9 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "mul(mat, mat)");
 }
@@ -242,6 +272,8 @@
   auto* expr =
       create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, left, right);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "(_tint_tmp)");
   EXPECT_EQ(pre_result(), R"(bool _tint_tmp = left;
@@ -263,6 +295,8 @@
       create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, a, b),
       create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, c, d));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "(_tint_tmp_0)");
   EXPECT_EQ(pre_result(), R"(bool _tint_tmp = a;
@@ -287,6 +321,8 @@
   auto* expr =
       create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, left, right);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "(_tint_tmp)");
   EXPECT_EQ(pre_result(), R"(bool _tint_tmp = left;
@@ -331,6 +367,8 @@
           else_stmt,
       });
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
   EXPECT_EQ(result(), R"(bool _tint_tmp = a;
 if (_tint_tmp) {
@@ -362,6 +400,8 @@
       ast::BinaryOp::kLogicalOr,
       create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, a, b), c));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
   EXPECT_EQ(result(), R"(bool _tint_tmp = a;
 if (_tint_tmp) {
@@ -388,6 +428,8 @@
           ast::BinaryOp::kLogicalAnd,
           create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, b, c), d));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
   EXPECT_EQ(result(), R"(bool _tint_tmp = b;
 if (!_tint_tmp) {
@@ -417,6 +459,8 @@
 
   auto* expr = create<ast::VariableDeclStatement>(var);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
   EXPECT_EQ(result(), R"(bool _tint_tmp = b;
 if (_tint_tmp) {
@@ -443,6 +487,8 @@
           ast::BinaryOp::kLogicalAnd, a,
           create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, b, c)));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(pre_result(), R"(bool _tint_tmp = a;
 if (_tint_tmp) {
@@ -477,6 +523,8 @@
 
   auto* expr = create<ast::CallStatement>(Call("foo", params));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, expr)) << gen.error();
   EXPECT_EQ(result(), R"(bool _tint_tmp = a;
 if (_tint_tmp) {
diff --git a/src/writer/hlsl/generator_impl_bitcast_test.cc b/src/writer/hlsl/generator_impl_bitcast_test.cc
index a6fc904..f4c9f39 100644
--- a/src/writer/hlsl/generator_impl_bitcast_test.cc
+++ b/src/writer/hlsl/generator_impl_bitcast_test.cc
@@ -33,6 +33,8 @@
   auto* id = Expr("id");
   auto* bitcast = create<ast::BitcastExpression>(ty.f32, id);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, bitcast)) << gen.error();
   EXPECT_EQ(result(), "asfloat(id)");
 }
@@ -41,6 +43,8 @@
   auto* id = Expr("id");
   auto* bitcast = create<ast::BitcastExpression>(ty.i32, id);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, bitcast)) << gen.error();
   EXPECT_EQ(result(), "asint(id)");
 }
@@ -49,6 +53,8 @@
   auto* id = Expr("id");
   auto* bitcast = create<ast::BitcastExpression>(ty.u32, id);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, bitcast)) << gen.error();
   EXPECT_EQ(result(), "asuint(id)");
 }
diff --git a/src/writer/hlsl/generator_impl_block_test.cc b/src/writer/hlsl/generator_impl_block_test.cc
index 304fe12..edb9be2 100644
--- a/src/writer/hlsl/generator_impl_block_test.cc
+++ b/src/writer/hlsl/generator_impl_block_test.cc
@@ -29,6 +29,9 @@
   auto* b = create<ast::BlockStatement>(ast::StatementList{
       create<ast::DiscardStatement>(),
   });
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, b)) << gen.error();
@@ -42,6 +45,9 @@
   auto* b = create<ast::BlockStatement>(ast::StatementList{
       create<ast::DiscardStatement>(),
   });
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitBlock(out, b)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_break_test.cc b/src/writer/hlsl/generator_impl_break_test.cc
index 54d26b8..e7b865c 100644
--- a/src/writer/hlsl/generator_impl_break_test.cc
+++ b/src/writer/hlsl/generator_impl_break_test.cc
@@ -29,6 +29,8 @@
 TEST_F(HlslGeneratorImplTest_Break, Emit_Break) {
   auto* b = create<ast::BreakStatement>();
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, b)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_call_test.cc b/src/writer/hlsl/generator_impl_call_test.cc
index 92b1905..23b2176 100644
--- a/src/writer/hlsl/generator_impl_call_test.cc
+++ b/src/writer/hlsl/generator_impl_call_test.cc
@@ -36,6 +36,8 @@
                     ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
   EXPECT_EQ(result(), "my_func()");
 }
@@ -47,6 +49,8 @@
                     ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
   EXPECT_EQ(result(), "my_func(param1, param2)");
 }
@@ -57,6 +61,9 @@
   auto* func = Func("my_func", ast::VariableList{}, ty.void_,
                     ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
   ASSERT_TRUE(gen.EmitStatement(out, call)) << gen.error();
   EXPECT_EQ(result(), "  my_func(param1, param2);\n");
diff --git a/src/writer/hlsl/generator_impl_case_test.cc b/src/writer/hlsl/generator_impl_case_test.cc
index d6fd895..b60e7e5 100644
--- a/src/writer/hlsl/generator_impl_case_test.cc
+++ b/src/writer/hlsl/generator_impl_case_test.cc
@@ -38,6 +38,8 @@
   lit.push_back(Literal(5));
   auto* c = create<ast::CaseStatement>(lit, body);
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitCase(out, c)) << gen.error();
@@ -53,6 +55,8 @@
   auto* c = create<ast::CaseStatement>(
       lit, create<ast::BlockStatement>(ast::StatementList{}));
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitCase(out, c)) << gen.error();
@@ -70,6 +74,8 @@
   lit.push_back(Literal(5));
   auto* c = create<ast::CaseStatement>(lit, body);
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitCase(out, c)) << gen.error();
@@ -88,6 +94,8 @@
   lit.push_back(Literal(6));
   auto* c = create<ast::CaseStatement>(lit, body);
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitCase(out, c)) << gen.error();
@@ -104,6 +112,8 @@
   });
   auto* c = create<ast::CaseStatement>(ast::CaseSelectorList{}, body);
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitCase(out, c)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_cast_test.cc b/src/writer/hlsl/generator_impl_cast_test.cc
index 6a8c533..de0d39f 100644
--- a/src/writer/hlsl/generator_impl_cast_test.cc
+++ b/src/writer/hlsl/generator_impl_cast_test.cc
@@ -30,12 +30,18 @@
 
 TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Scalar) {
   auto* cast = Construct<f32>("id");
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, cast)) << gen.error();
   EXPECT_EQ(result(), "float(id)");
 }
 
 TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Vector) {
   auto* cast = vec3<f32>("id");
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, cast)) << gen.error();
   EXPECT_EQ(result(), "float3(id)");
 }
diff --git a/src/writer/hlsl/generator_impl_constructor_test.cc b/src/writer/hlsl/generator_impl_constructor_test.cc
index 0eaeb36..071d240 100644
--- a/src/writer/hlsl/generator_impl_constructor_test.cc
+++ b/src/writer/hlsl/generator_impl_constructor_test.cc
@@ -38,6 +38,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Bool) {
   auto* expr = Expr(false);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "false");
 }
@@ -45,6 +47,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Int) {
   auto* expr = Expr(-12345);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "-12345");
 }
@@ -52,6 +56,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_UInt) {
   auto* expr = Expr(56779u);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "56779u");
 }
@@ -60,6 +66,8 @@
   // Use a number close to 1<<30 but whose decimal representation ends in 0.
   auto* expr = Expr(static_cast<float>((1 << 30) - 4));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "1073741824.0f");
 }
@@ -67,6 +75,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
   auto* expr = Construct<f32>(-1.2e-5f);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "float(-0.000012f)");
 }
@@ -74,6 +84,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Bool) {
   auto* expr = Construct<bool>(true);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "bool(true)");
 }
@@ -81,6 +93,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Int) {
   auto* expr = Construct<i32>(-12345);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "int(-12345)");
 }
@@ -88,6 +102,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Uint) {
   auto* expr = Construct<u32>(12345u);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "uint(12345u)");
 }
@@ -95,6 +111,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
   auto* expr = vec3<f32>(1.f, 2.f, 3.f);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "float3(1.0f, 2.0f, 3.0f)");
 }
@@ -102,6 +120,8 @@
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
   auto* expr = vec3<f32>();
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "float3(0.0f)");
 }
@@ -112,6 +132,8 @@
 
   auto* expr = mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
 
   // A matrix of type T with n columns and m rows can also be constructed from
@@ -124,6 +146,8 @@
   auto* expr = Construct(ty.array(ty.vec3<f32>(), 3), vec3<f32>(1.f, 2.f, 3.f),
                          vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f));
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitConstructor(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f),"
diff --git a/src/writer/hlsl/generator_impl_continue_test.cc b/src/writer/hlsl/generator_impl_continue_test.cc
index 7e7aec4..f87de21 100644
--- a/src/writer/hlsl/generator_impl_continue_test.cc
+++ b/src/writer/hlsl/generator_impl_continue_test.cc
@@ -29,6 +29,8 @@
 TEST_F(HlslGeneratorImplTest_Continue, Emit_Continue) {
   auto* c = create<ast::ContinueStatement>();
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, c)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_discard_test.cc b/src/writer/hlsl/generator_impl_discard_test.cc
index cd96c69..9d0c425 100644
--- a/src/writer/hlsl/generator_impl_discard_test.cc
+++ b/src/writer/hlsl/generator_impl_discard_test.cc
@@ -26,6 +26,8 @@
 TEST_F(HlslGeneratorImplTest_Discard, Emit_Discard) {
   auto* stmt = create<ast::DiscardStatement>();
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
index ae627c8..3f4e9ee 100644
--- a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
@@ -75,6 +75,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(result(), R"(struct vtx_main_in {
   float foo : TEXCOORD0;
@@ -125,6 +128,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(result(), R"(struct vtx_main_out {
   float foo : TEXCOORD0;
@@ -175,6 +181,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(result(), R"(struct main_in {
   float foo : TEXCOORD0;
@@ -225,6 +234,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(result(), R"(struct main_out {
   float foo : SV_Target0;
@@ -272,6 +284,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_FALSE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(gen.error(), R"(invalid location variable for pipeline stage)");
 }
@@ -314,6 +329,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_FALSE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(gen.error(), R"(invalid location variable for pipeline stage)");
 }
@@ -364,6 +382,9 @@
   std::unordered_set<Symbol> globals;
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitEntryPointData(out, func, globals)) << gen.error();
   EXPECT_EQ(result(), R"(struct main_in {
   float4 coord : SV_Position;
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index ee5e40b..e5a8570 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -60,6 +60,9 @@
                     ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
@@ -78,6 +81,9 @@
                     ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
@@ -100,6 +106,9 @@
            ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
@@ -122,6 +131,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(void main() {
   return;
@@ -160,6 +172,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct main_in {
   float foo : TEXCOORD0;
@@ -209,6 +224,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct frag_main_in {
   float foo : TEXCOORD0;
@@ -261,6 +279,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct frag_main_in {
   float4 coord : SV_Position;
@@ -307,6 +328,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0) {
   float4 coord;
@@ -357,6 +381,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct Uniforms {
   float4 coord;
@@ -407,6 +434,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(RWByteAddressBuffer coord : register(u0);
 
@@ -454,6 +484,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(ByteAddressBuffer coord : register(u0);
 
@@ -498,6 +531,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(RWByteAddressBuffer coord : register(u0);
 
@@ -512,7 +548,6 @@
 TEST_F(
     HlslGeneratorImplTest_Function,
     Emit_FunctionDecoration_Called_By_EntryPoints_WithLocationGlobals_And_Params) {  // NOLINT
-
   auto* foo_var = Var("foo", ast::StorageClass::kInput, ty.f32, nullptr,
                       ast::VariableDecorationList{
                           create<ast::LocationDecoration>(0),
@@ -562,6 +597,9 @@
   mod->AddFunction(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct ep_1_in {
   float foo : TEXCOORD0;
@@ -624,6 +662,9 @@
   mod->AddFunction(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct ep_1_out {
   float depth : SV_Depth;
@@ -645,7 +686,6 @@
 TEST_F(
     HlslGeneratorImplTest_Function,
     Emit_FunctionDecoration_Called_By_EntryPoints_WithBuiltinGlobals_And_Params) {  // NOLINT
-
   auto* coord_var =
       Var("coord", ast::StorageClass::kInput, ty.vec4<f32>(), nullptr,
           ast::VariableDecorationList{
@@ -691,6 +731,9 @@
   mod->AddFunction(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct ep_1_in {
   float4 coord : SV_Position;
@@ -754,6 +797,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(cbuffer cbuffer_coord : register(b0) {
   float4 coord;
@@ -811,6 +857,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(RWByteAddressBuffer coord : register(u0);
 
@@ -856,6 +905,9 @@
   mod->AddFunction(func_1);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct ep_1_out {
   float bar : SV_Target1;
@@ -883,6 +935,8 @@
 
   mod->AddFunction(func);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(void GeometryShader_tint_0() {
   return;
@@ -905,6 +959,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"([numthreads(1, 1, 1)]
 void main() {
@@ -929,6 +986,9 @@
   mod->AddFunction(func);
 
   ASSERT_TRUE(td.Determine()) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"([numthreads(2, 4, 6)]
 void main() {
@@ -949,6 +1009,9 @@
       ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
@@ -1029,6 +1092,8 @@
   }
 
   ASSERT_TRUE(td.Determine()) << td.error();
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(struct Data {
   float d;
diff --git a/src/writer/hlsl/generator_impl_identifier_test.cc b/src/writer/hlsl/generator_impl_identifier_test.cc
index eba1c18..eaaebc1 100644
--- a/src/writer/hlsl/generator_impl_identifier_test.cc
+++ b/src/writer/hlsl/generator_impl_identifier_test.cc
@@ -25,6 +25,9 @@
 
 TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
   auto* i = Expr("foo");
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, i)) << gen.error();
   EXPECT_EQ(result(), "foo");
 }
@@ -32,6 +35,9 @@
 TEST_F(HlslGeneratorImplTest_Identifier,
        EmitIdentifierExpression_Single_WithCollision) {
   auto* i = Expr("virtual");
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, i)) << gen.error();
   EXPECT_EQ(result(), "virtual_tint_0");
 }
diff --git a/src/writer/hlsl/generator_impl_if_test.cc b/src/writer/hlsl/generator_impl_if_test.cc
index 3825a10..1e67070 100644
--- a/src/writer/hlsl/generator_impl_if_test.cc
+++ b/src/writer/hlsl/generator_impl_if_test.cc
@@ -32,8 +32,10 @@
       create<ast::ReturnStatement>(),
   });
   auto* i = create<ast::IfStatement>(cond, body, ast::ElseStatementList{});
-  gen.increment_indent();
 
+  GeneratorImpl& gen = Build();
+
+  gen.increment_indent();
   ASSERT_TRUE(gen.EmitStatement(out, i)) << gen.error();
   EXPECT_EQ(result(), R"(  if (cond) {
     return;
@@ -55,6 +57,8 @@
       cond, body,
       ast::ElseStatementList{create<ast::ElseStatement>(else_cond, else_body)});
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, i)) << gen.error();
@@ -81,6 +85,8 @@
       cond, body,
       ast::ElseStatementList{create<ast::ElseStatement>(nullptr, else_body)});
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, i)) << gen.error();
@@ -114,6 +120,8 @@
           create<ast::ElseStatement>(nullptr, else_body_2),
       });
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, i)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_import_test.cc b/src/writer/hlsl/generator_impl_import_test.cc
index 8b68fcc..8613a0d 100644
--- a/src/writer/hlsl/generator_impl_import_test.cc
+++ b/src/writer/hlsl/generator_impl_import_test.cc
@@ -54,6 +54,9 @@
   auto* expr = Call(ident, 1.f);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1.0f)");
 }
@@ -92,6 +95,9 @@
   auto* expr = Call(param.name, Expr(1));
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1)");
 }
@@ -106,6 +112,9 @@
   auto* expr = Call(param.name, 1.f, 2.f);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1.0f, 2.0f)");
 }
@@ -127,6 +136,9 @@
       Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             std::string(param.hlsl_name) +
@@ -143,6 +155,9 @@
   auto* expr = Call(param.name, 1, 2);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2)");
 }
@@ -158,6 +173,9 @@
   auto* expr = Call(param.name, 1.f, 2.f, 3.f);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1.0f, 2.0f, 3.0f)");
 }
@@ -180,6 +198,9 @@
   auto* expr = Call(param.name, 1, 2, 3);
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string(param.hlsl_name) + "(1, 2, 3)");
 }
@@ -197,6 +218,9 @@
   // Register the global
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitCall(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), std::string("determinant(var)"));
 }
diff --git a/src/writer/hlsl/generator_impl_intrinsic_test.cc b/src/writer/hlsl/generator_impl_intrinsic_test.cc
index 79000d5..a3b0a71 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_test.cc
@@ -38,6 +38,9 @@
 using HlslIntrinsicTest = TestParamHelper<IntrinsicData>;
 TEST_P(HlslIntrinsicTest, Emit) {
   auto param = GetParam();
+
+  GeneratorImpl& gen = Build();
+
   EXPECT_EQ(gen.generate_intrinsic_name(param.intrinsic), param.hlsl_name);
 }
 INSTANTIATE_TEST_SUITE_P(
@@ -71,6 +74,8 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Intrinsic, Intrinsic_Bad_Name) {
+  GeneratorImpl& gen = Build();
+
   EXPECT_EQ(gen.generate_intrinsic_name(ast::Intrinsic::kNone), "");
 }
 
@@ -85,6 +90,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(call)) << td.error();
 
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
   EXPECT_EQ(result(), "  dot(param1, param2)");
diff --git a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
index 30fab52..a0194ec 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_texture_test.cc
@@ -22,6 +22,7 @@
 #include "src/type/sampled_texture_type.h"
 #include "src/type_determiner.h"
 #include "src/writer/hlsl/generator_impl.h"
+#include "src/writer/hlsl/test_helper.h"
 
 namespace tint {
 namespace writer {
@@ -404,26 +405,11 @@
 }  // NOLINT - Ignore the length of this function
 
 class HlslGeneratorIntrinsicTextureTest
-    : public ast::BuilderWithModule,
-      public testing::TestWithParam<ast::intrinsic::test::TextureOverloadCase> {
+    : public TestParamHelper<ast::intrinsic::test::TextureOverloadCase> {
  protected:
   void OnVariableBuilt(ast::Variable* var) override {
     td.RegisterVariableForTesting(var);
   }
-
-  /// @returns the result string
-  std::string result() const { return out.str(); }
-  /// @returns the pre result string
-  std::string pre_result() const { return pre.str(); }
-
-  /// The type determiner
-  TypeDeterminer td{mod};
-  /// The generator
-  GeneratorImpl gen{mod};
-  /// The output stream
-  std::ostringstream out;
-  /// The pre-output stream
-  std::ostringstream pre;
 };
 
 TEST_P(HlslGeneratorIntrinsicTextureTest, Call) {
@@ -437,6 +423,8 @@
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(call)) << td.error();
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
 
   auto expected = expected_texture_overload(param.overload);
diff --git a/src/writer/hlsl/generator_impl_loop_test.cc b/src/writer/hlsl/generator_impl_loop_test.cc
index 100e21d..09befb2 100644
--- a/src/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/writer/hlsl/generator_impl_loop_test.cc
@@ -38,6 +38,9 @@
       create<ast::DiscardStatement>(),
   });
   auto* l = create<ast::LoopStatement>(body, nullptr);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, l)) << gen.error();
@@ -55,6 +58,9 @@
       create<ast::ReturnStatement>(),
   });
   auto* l = create<ast::LoopStatement>(body, continuing);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, l)) << gen.error();
@@ -93,6 +99,9 @@
   });
 
   auto* outer = create<ast::LoopStatement>(body, continuing);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, outer)) << gen.error();
@@ -158,6 +167,9 @@
       create<ast::AssignmentStatement>(lhs, rhs),
   });
   auto* outer = create<ast::LoopStatement>(body, continuing);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, outer)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 3121135..e1ade73 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -46,13 +46,17 @@
 
   auto* s = ty.struct_("Str", strct);
   auto* str_var = Var("str", ast::StorageClass::kPrivate, s);
+  mod->AddGlobalVariable(str_var);
+
   auto* expr = MemberAccessor("str", "mem");
 
   td.RegisterVariableForTesting(str_var);
-  gen.register_global(str_var);
-  mod->AddGlobalVariable(str_var);
-
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(str_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "str.mem");
 }
@@ -75,15 +79,18 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-  auto* expr = MemberAccessor("data", "b");
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
+  auto* expr = MemberAccessor("data", "b");
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load(4))");
 }
@@ -105,18 +112,22 @@
       ast::StructDecorationList{});
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-  auto* expr = MemberAccessor("data", "a");
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
+  auto* expr = MemberAccessor("data", "a");
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asint(data.Load(0))");
 }
+
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_MemberAccessor_StorageBuffer_Store_Matrix) {
   // struct Data {
@@ -138,7 +149,9 @@
 
   auto* s = ty.struct_("Data", str);
   auto* b_var = Var("b", ast::StorageClass::kPrivate, ty.mat2x3<f32>());
+  mod->AddGlobalVariable(b_var);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
+  mod->AddGlobalVariable(coord_var);
 
   auto* lhs = MemberAccessor("data", "a");
   auto* rhs = Expr("b");
@@ -147,14 +160,15 @@
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(b_var);
-  gen.register_global(coord_var);
-  gen.register_global(b_var);
-  mod->AddGlobalVariable(coord_var);
-  mod->AddGlobalVariable(b_var);
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+  gen.register_global(b_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(), R"(float3x2 _tint_tmp = b;
 data.Store3(4 + 0, asuint(_tint_tmp[0]));
@@ -183,19 +197,21 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
+  mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = MemberAccessor("data", "a");
   auto* rhs = Construct(ty.mat2x3<f32>(), ast::ExpressionList{});
 
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
-  mod->AddGlobalVariable(coord_var);
-
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(
       result(),
@@ -224,16 +240,18 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
+  mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr = MemberAccessor("data", "a");
 
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
-  mod->AddGlobalVariable(coord_var);
-
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "asfloat(uint2x3(data.Load2(4 + 0), data.Load2(4 + 8), "
@@ -264,15 +282,18 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-  auto* expr = MemberAccessor("data", "a");
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
+  auto* expr = MemberAccessor("data", "a");
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "asfloat(uint3x2(data.Load3(4 + 0), data.Load3(4 + 16)))");
@@ -296,15 +317,18 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-  auto* expr = MemberAccessor("data", "a");
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
+  auto* expr = MemberAccessor("data", "a");
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(),
             "asfloat(uint3x3(data.Load3(0 + 0), data.Load3(0 + 16), "
@@ -329,16 +353,19 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
+  mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
   auto* expr = IndexAccessor(
       IndexAccessor(MemberAccessor("data", "a"), Expr(2)), Expr(1));
 
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
-  mod->AddGlobalVariable(coord_var);
-
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + (16 * 2) + 16))");
 }
@@ -362,15 +389,18 @@
       ast::StructDecorationList{});
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-  auto* expr = IndexAccessor(MemberAccessor("data", "a"), Expr(2));
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
+  auto* expr = IndexAccessor(MemberAccessor("data", "a"), Expr(2));
 
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asint(data.Load((4 * 2) + 0))");
 }
@@ -394,16 +424,19 @@
       ast::StructDecorationList{});
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
+  mod->AddGlobalVariable(coord_var);
+  td.RegisterVariableForTesting(coord_var);
+
   auto* expr = IndexAccessor(MemberAccessor("data", "a"),
                              Sub(Add(Expr(2), Expr(4)), Expr(3)));
 
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
-  mod->AddGlobalVariable(coord_var);
-
   ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asint(data.Load((4 * ((2 + 4) - 3)) + 0))");
 }
@@ -426,18 +459,20 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = MemberAccessor("data", "b");
   auto* rhs = Expr(2.0f);
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(), R"(data.Store(4, asuint(2.0f));
 )");
@@ -464,18 +499,20 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = IndexAccessor(MemberAccessor("data", "a"), Expr(2));
   auto* rhs = Expr(2);
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign)) << td.error();
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(), R"(data.Store((4 * 2) + 0, asuint(2));
 )");
@@ -499,18 +536,20 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = MemberAccessor("data", "a");
   auto* rhs = Expr(2);
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(), R"(data.Store(0, asuint(2));
 )");
@@ -534,16 +573,18 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr = MemberAccessor("data", "b");
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load3(16))");
 }
@@ -566,19 +607,21 @@
 
   auto* s = ty.struct_("Data", str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, s);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = MemberAccessor("data", "b");
   auto* rhs = vec3<f32>(1.f, 2.f, 3.f);
 
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(),
             R"(data.Store3(16, asuint(float3(1.0f, 2.0f, 3.0f)));
@@ -619,17 +662,19 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr =
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b");
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0))");
 }
@@ -666,18 +711,21 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
 
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr = MemberAccessor(
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b"),
       "xy");
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load3(16 + (32 * 2) + 0)).xy");
 }
@@ -717,18 +765,20 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr = MemberAccessor(
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b"),
       "g");
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
 }
@@ -767,18 +817,20 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* expr = IndexAccessor(
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b"),
       Expr(1));
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(expr));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, expr)) << gen.error();
   EXPECT_EQ(result(), "asfloat(data.Load((4 * 1) + 16 + (32 * 2) + 0))");
 }
@@ -817,12 +869,8 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs =
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b");
@@ -830,7 +878,13 @@
   auto* assign =
       create<ast::AssignmentStatement>(lhs, vec3<f32>(1.f, 2.f, 3.f));
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(),
             R"(data.Store3(16 + (32 * 2) + 0, asuint(float3(1.0f, 2.0f, 3.0f)));
@@ -871,12 +925,8 @@
 
   auto* pre_struct = ty.struct_("Pre", pre_str);
   auto* coord_var = Var("data", ast::StorageClass::kStorage, pre_struct);
-
-  td.RegisterVariableForTesting(coord_var);
-  gen.register_global(coord_var);
   mod->AddGlobalVariable(coord_var);
-
-  ASSERT_TRUE(td.Determine()) << td.error();
+  td.RegisterVariableForTesting(coord_var);
 
   auto* lhs = MemberAccessor(
       MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), Expr(2)), "b"),
@@ -885,7 +935,13 @@
 
   auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
 
+  ASSERT_TRUE(td.Determine()) << td.error();
   ASSERT_TRUE(td.DetermineResultType(assign));
+
+  GeneratorImpl& gen = Build();
+
+  gen.register_global(coord_var);
+
   ASSERT_TRUE(gen.EmitStatement(out, assign)) << gen.error();
   EXPECT_EQ(result(),
             R"(data.Store((4 * 1) + 16 + (32 * 2) + 0, asuint(1.0f));
diff --git a/src/writer/hlsl/generator_impl_module_constant_test.cc b/src/writer/hlsl/generator_impl_module_constant_test.cc
index b8ec558..057162f 100644
--- a/src/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/writer/hlsl/generator_impl_module_constant_test.cc
@@ -19,10 +19,10 @@
 #include "src/ast/float_literal.h"
 #include "src/ast/module.h"
 #include "src/ast/scalar_constructor_expression.h"
-#include "src/type/array_type.h"
-#include "src/type/f32_type.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/variable.h"
+#include "src/type/array_type.h"
+#include "src/type/f32_type.h"
 #include "src/writer/hlsl/test_helper.h"
 
 namespace tint {
@@ -37,6 +37,8 @@
       Const("pos", ast::StorageClass::kNone, ty.array<f32, 3>(),
             array<f32, 3>(1.f, 2.f, 3.f), ast::VariableDecorationList{});
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
 }
@@ -47,6 +49,8 @@
                         create<ast::ConstantIdDecoration>(23),
                     });
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #define WGSL_SPEC_CONSTANT_23 3.0f
@@ -62,6 +66,8 @@
                         create<ast::ConstantIdDecoration>(23),
                     });
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #error spec constant required for constant id 23
diff --git a/src/writer/hlsl/generator_impl_return_test.cc b/src/writer/hlsl/generator_impl_return_test.cc
index 92939e4..4c04d90 100644
--- a/src/writer/hlsl/generator_impl_return_test.cc
+++ b/src/writer/hlsl/generator_impl_return_test.cc
@@ -29,6 +29,9 @@
 
 TEST_F(HlslGeneratorImplTest_Return, Emit_Return) {
   auto* r = create<ast::ReturnStatement>();
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, r)) << gen.error();
@@ -37,6 +40,9 @@
 
 TEST_F(HlslGeneratorImplTest_Return, Emit_ReturnWithValue) {
   auto* r = create<ast::ReturnStatement>(Expr("expr"));
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, r)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_switch_test.cc b/src/writer/hlsl/generator_impl_switch_test.cc
index 17d8666..75039eb 100644
--- a/src/writer/hlsl/generator_impl_switch_test.cc
+++ b/src/writer/hlsl/generator_impl_switch_test.cc
@@ -51,6 +51,9 @@
 
   auto* cond = Expr("cond");
   auto* s = create<ast::SwitchStatement>(cond, body);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, s)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc
index 27476ae..a4f4ffc 100644
--- a/src/writer/hlsl/generator_impl_test.cc
+++ b/src/writer/hlsl/generator_impl_test.cc
@@ -32,6 +32,8 @@
                     ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
   EXPECT_EQ(result(), R"(void my_func() {
 }
@@ -40,11 +42,15 @@
 }
 
 TEST_F(HlslGeneratorImplTest, InputStructName) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_EQ(gen.generate_name("func_main_in"), "func_main_in");
 }
 
 TEST_F(HlslGeneratorImplTest, InputStructName_ConflictWithExisting) {
   // Register the struct name as existing.
+  GeneratorImpl& gen = Build();
+
   auto* namer = gen.namer_for_testing();
   namer->NameFor("func_main_out");
 
@@ -52,9 +58,12 @@
 }
 
 TEST_F(HlslGeneratorImplTest, NameConflictWith_InputStructName) {
-  ASSERT_EQ(gen.generate_name("func_main_in"), "func_main_in");
+  auto* expr = Expr("func_main_in");
 
-  ASSERT_TRUE(gen.EmitIdentifier(pre, out, Expr("func_main_in")));
+  GeneratorImpl& gen = Build();
+
+  ASSERT_EQ(gen.generate_name("func_main_in"), "func_main_in");
+  ASSERT_TRUE(gen.EmitIdentifier(pre, out, expr));
   EXPECT_EQ(result(), "func_main_in_0");
 }
 
@@ -69,6 +78,8 @@
 using HlslBuiltinConversionTest = TestParamHelper<HlslBuiltinData>;
 TEST_P(HlslBuiltinConversionTest, Emit) {
   auto params = GetParam();
+  GeneratorImpl& gen = Build();
+
   EXPECT_EQ(gen.builtin_to_attribute(params.builtin),
             std::string(params.attribute_name));
 }
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 2655b22..2d69d2b 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -47,6 +47,8 @@
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Alias) {
   auto* alias = ty.alias("alias", ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, alias, "")) << gen.error();
   EXPECT_EQ(result(), "alias");
 }
@@ -54,17 +56,24 @@
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Alias_NameCollision) {
   auto* alias = ty.alias("bool", ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, alias, "")) << gen.error();
   EXPECT_EQ(result(), "bool_tint_0");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.array<bool, 4>(), "ary")) << gen.error();
   EXPECT_EQ(result(), "bool ary[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
   auto* arr = ty.array(ty.array<bool, 4>(), 5);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, arr, "ary")) << gen.error();
   EXPECT_EQ(result(), "bool ary[5][4]");
 }
@@ -73,53 +82,75 @@
 TEST_F(HlslGeneratorImplTest_Type,
        DISABLED_EmitType_ArrayOfArrayOfRuntimeArray) {
   auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5), 0);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, arr, "ary")) << gen.error();
   EXPECT_EQ(result(), "bool ary[5][4][1]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
   auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5), 6);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, arr, "ary")) << gen.error();
   EXPECT_EQ(result(), "bool ary[6][5][4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_NameCollision) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.array<bool, 4>(), "bool")) << gen.error();
   EXPECT_EQ(result(), "bool bool_tint_0[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.array<bool, 4>(), "")) << gen.error();
   EXPECT_EQ(result(), "bool[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_RuntimeArray) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.array<bool>(), "ary")) << gen.error();
   EXPECT_EQ(result(), "bool ary[]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type,
        DISABLED_EmitType_RuntimeArray_NameCollision) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.array<bool>(), "double")) << gen.error();
   EXPECT_EQ(result(), "bool double_tint_0[]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Bool) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.bool_, "")) << gen.error();
   EXPECT_EQ(result(), "bool");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_F32) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.f32, "")) << gen.error();
   EXPECT_EQ(result(), "float");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_I32) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.i32, "")) << gen.error();
   EXPECT_EQ(result(), "int");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.mat2x3<f32>(), "")) << gen.error();
   EXPECT_EQ(result(), "float3x2");
 }
@@ -128,6 +159,8 @@
 TEST_F(HlslGeneratorImplTest_Type, DISABLED_EmitType_Pointer) {
   type::Pointer p(ty.f32, ast::StorageClass::kWorkgroup);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &p, "")) << gen.error();
   EXPECT_EQ(result(), "float*");
 }
@@ -139,6 +172,8 @@
       ast::StructDecorationList{});
 
   auto* s = ty.struct_("S", str);
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error();
   EXPECT_EQ(result(), R"(struct S {
   int a;
@@ -154,6 +189,8 @@
       ast::StructDecorationList{});
 
   auto* s = ty.struct_("S", str);
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, s, "")) << gen.error();
   EXPECT_EQ(result(), "S");
 }
@@ -166,6 +203,8 @@
       ast::StructDecorationList{});
 
   auto* s = ty.struct_("S", str);
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, s, "")) << gen.error();
   EXPECT_EQ(result(), R"(struct {
   int8_t pad_0[4];
@@ -183,6 +222,8 @@
       ast::StructDecorationList{});
 
   auto* s = ty.struct_("S", str);
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStructType(out, s, "S")) << gen.error();
   EXPECT_EQ(result(), R"(struct S {
   int double_tint_0;
@@ -202,6 +243,8 @@
       decos);
 
   auto* s = ty.struct_("S", str);
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStructType(out, s, "B")) << gen.error();
   EXPECT_EQ(result(), R"(struct B {
   int a;
@@ -210,16 +253,22 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_U32) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.u32, "")) << gen.error();
   EXPECT_EQ(result(), "uint");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Vector) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.vec3<f32>(), "")) << gen.error();
   EXPECT_EQ(result(), "float3");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Void) {
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, ty.void_, "")) << gen.error();
   EXPECT_EQ(result(), "void");
 }
@@ -227,6 +276,8 @@
 TEST_F(HlslGeneratorImplTest_Type, EmitSampler) {
   type::Sampler sampler(type::SamplerKind::kSampler);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &sampler, "")) << gen.error();
   EXPECT_EQ(result(), "SamplerState");
 }
@@ -234,6 +285,8 @@
 TEST_F(HlslGeneratorImplTest_Type, EmitSamplerComparison) {
   type::Sampler sampler(type::SamplerKind::kComparisonSampler);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &sampler, "")) << gen.error();
   EXPECT_EQ(result(), "SamplerComparisonState");
 }
@@ -252,6 +305,8 @@
 
   type::DepthTexture s(params.dim);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
@@ -280,6 +335,8 @@
 
   type::SampledTexture s(params.dim, ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
@@ -299,6 +356,8 @@
 TEST_F(HlslGeneratorImplTest_Type, EmitMultisampledTexture) {
   type::MultisampledTexture s(type::TextureDimension::k2d, ty.f32);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
   EXPECT_EQ(result(), "Texture2D");
 }
@@ -323,6 +382,8 @@
                                    : ast::AccessControl::kWriteOnly,
                          &s);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitType(out, &ac, "")) << gen.error();
   EXPECT_EQ(result(), params.result);
 }
diff --git a/src/writer/hlsl/generator_impl_unary_op_test.cc b/src/writer/hlsl/generator_impl_unary_op_test.cc
index 77fdf7a..48294c1 100644
--- a/src/writer/hlsl/generator_impl_unary_op_test.cc
+++ b/src/writer/hlsl/generator_impl_unary_op_test.cc
@@ -40,6 +40,8 @@
   auto* expr = Expr("expr");
   auto* op = create<ast::UnaryOpExpression>(params.op, expr);
 
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitExpression(pre, out, op)) << gen.error();
   EXPECT_EQ(result(), std::string(params.name) + "(expr)");
 }
diff --git a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index 10e62fe..91ca67e 100644
--- a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -36,6 +36,9 @@
   auto* var = Var("a", ast::StorageClass::kNone, ty.f32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
@@ -46,6 +49,9 @@
   auto* var = Const("a", ast::StorageClass::kNone, ty.f32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
@@ -56,6 +62,9 @@
   auto* var = Var("a", ast::StorageClass::kNone, ty.array<f32, 5>());
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
@@ -67,6 +76,9 @@
   auto* var = Var("a", ast::StorageClass::kFunction, ty.f32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
@@ -77,6 +89,9 @@
   auto* var = Var("a", ast::StorageClass::kPrivate, ty.f32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
@@ -89,6 +104,9 @@
                   ast::VariableDecorationList{});
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
   EXPECT_EQ(result(), R"(float a = initializer;
 )");
@@ -100,6 +118,9 @@
                   ast::VariableDecorationList{});
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
   EXPECT_EQ(result(), R"(float3 a = float3(0.0f);
 )");
@@ -111,6 +132,9 @@
                   mat2x3<f32>(), ast::VariableDecorationList{});
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
+
+  GeneratorImpl& gen = Build();
+
   ASSERT_TRUE(gen.EmitStatement(out, stmt)) << gen.error();
   EXPECT_EQ(result(),
             R"(float3x2 a = float3x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
diff --git a/src/writer/hlsl/test_helper.h b/src/writer/hlsl/test_helper.h
index fd874f4..af3d10a 100644
--- a/src/writer/hlsl/test_helper.h
+++ b/src/writer/hlsl/test_helper.h
@@ -33,9 +33,21 @@
 template <typename BODY>
 class TestHelperBase : public BODY, public ast::BuilderWithModule {
  public:
-  TestHelperBase() : td(mod), gen(mod) {}
+  TestHelperBase() : td(mod) {}
   ~TestHelperBase() = default;
 
+  /// Builds and returns a GeneratorImpl from the module.
+  /// @note The generator is only built once. Multiple calls to Build() will
+  /// return the same GeneratorImpl without rebuilding.
+  /// @return the built generator
+  GeneratorImpl& Build() {
+    if (gen_) {
+      return *gen_;
+    }
+    gen_ = std::make_unique<GeneratorImpl>(mod);
+    return *gen_;
+  }
+
   /// @returns the result string
   std::string result() const { return out.str(); }
 
@@ -44,13 +56,14 @@
 
   /// The type determiner
   TypeDeterminer td;
-  /// The generator
-  GeneratorImpl gen;
 
   /// The output stream
   std::ostringstream out;
   /// The pre-output stream
   std::ostringstream pre;
+
+ private:
+  std::unique_ptr<GeneratorImpl> gen_;
 };
 using TestHelper = TestHelperBase<testing::Test>;