writer/wgsl: Fix all tests that had unreachable AST nodes

By making nodes reachable, the resolver has now caught a whole lot of additional problems, which have been fixed in this CL.

Some of these broken tests were attempting to use private and workgroup variables as function-scope declarations.
This is not legal, and these have been moved to module-scope variables.

Bug: tint:469
Change-Id: If5e812da3f62f096e344c50782ab0f465ae74ea3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/48224
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/writer/wgsl/generator_impl_array_accessor_test.cc b/src/writer/wgsl/generator_impl_array_accessor_test.cc
index e755d42..77137ae 100644
--- a/src/writer/wgsl/generator_impl_array_accessor_test.cc
+++ b/src/writer/wgsl/generator_impl_array_accessor_test.cc
@@ -21,11 +21,10 @@
 
 using WgslGeneratorImplTest = TestHelper;
 
-TEST_F(WgslGeneratorImplTest, EmitExpression_ArrayAccessor) {
-  auto* idx = Expr(5);
-  auto* ary = Expr("ary");
-
-  auto* expr = create<ast::ArrayAccessorExpression>(ary, idx);
+TEST_F(WgslGeneratorImplTest, ArrayAccessor) {
+  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+  auto* expr = IndexAccessor("ary", 5);
+  WrapInFunction(expr);
 
   GeneratorImpl& gen = Build();
 
@@ -33,18 +32,6 @@
   EXPECT_EQ(gen.result(), "ary[5]");
 }
 
-TEST_F(WgslGeneratorImplTest, EmitArrayAccessor) {
-  auto* ary = Expr("ary");
-  auto* idx = Expr("idx");
-
-  auto* expr = create<ast::ArrayAccessorExpression>(ary, idx);
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.EmitArrayAccessor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "ary[idx]");
-}
-
 }  // namespace
 }  // namespace wgsl
 }  // namespace writer
diff --git a/src/writer/wgsl/generator_impl_assign_test.cc b/src/writer/wgsl/generator_impl_assign_test.cc
index 7113b03..1144eb1 100644
--- a/src/writer/wgsl/generator_impl_assign_test.cc
+++ b/src/writer/wgsl/generator_impl_assign_test.cc
@@ -22,9 +22,10 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Assign) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
-  auto* assign = create<ast::AssignmentStatement>(lhs, rhs);
+  Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
+  Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
+  auto* assign = create<ast::AssignmentStatement>(Expr("lhs"), Expr("rhs"));
+  WrapInFunction(assign);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_binary_test.cc b/src/writer/wgsl/generator_impl_binary_test.cc
index 02f3129..e83bd88 100644
--- a/src/writer/wgsl/generator_impl_binary_test.cc
+++ b/src/writer/wgsl/generator_impl_binary_test.cc
@@ -35,6 +35,7 @@
   auto* right = Expr("right");
 
   auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+  WrapInFunction(expr);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_bitcast_test.cc b/src/writer/wgsl/generator_impl_bitcast_test.cc
index e2e2d2c..9608196 100644
--- a/src/writer/wgsl/generator_impl_bitcast_test.cc
+++ b/src/writer/wgsl/generator_impl_bitcast_test.cc
@@ -22,13 +22,13 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Bitcast) {
-  auto* id = Expr("id");
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), id);
+  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1));
+  WrapInFunction(bitcast);
 
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitExpression(bitcast)) << gen.error();
-  EXPECT_EQ(gen.result(), "bitcast<f32>(id)");
+  EXPECT_EQ(gen.result(), "bitcast<f32>(1)");
 }
 
 }  // namespace
diff --git a/src/writer/wgsl/generator_impl_block_test.cc b/src/writer/wgsl/generator_impl_block_test.cc
index a67fcd0..27a0608 100644
--- a/src/writer/wgsl/generator_impl_block_test.cc
+++ b/src/writer/wgsl/generator_impl_block_test.cc
@@ -22,9 +22,8 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Block) {
-  auto* b = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  auto* b = Block(create<ast::DiscardStatement>());
+  WrapInFunction(b);
 
   GeneratorImpl& gen = Build();
 
@@ -38,9 +37,9 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Block_WithoutNewline) {
-  auto* b = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  auto* b = Block(create<ast::DiscardStatement>());
+  WrapInFunction(b);
+
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
diff --git a/src/writer/wgsl/generator_impl_break_test.cc b/src/writer/wgsl/generator_impl_break_test.cc
index cd75417..8585323 100644
--- a/src/writer/wgsl/generator_impl_break_test.cc
+++ b/src/writer/wgsl/generator_impl_break_test.cc
@@ -23,6 +23,7 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_Break) {
   auto* b = create<ast::BreakStatement>();
+  WrapInFunction(Loop(Block(b)));
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_call_test.cc b/src/writer/wgsl/generator_impl_call_test.cc
index 5c50689..bf701cd 100644
--- a/src/writer/wgsl/generator_impl_call_test.cc
+++ b/src/writer/wgsl/generator_impl_call_test.cc
@@ -23,8 +23,11 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
-  auto* id = Expr("my_func");
-  auto* call = create<ast::CallExpression>(id, ast::ExpressionList{});
+  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
+       ast::DecorationList{});
+
+  auto* call = Call("my_func");
+  WrapInFunction(call);
 
   GeneratorImpl& gen = Build();
 
@@ -33,9 +36,13 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithParams) {
-  auto* id = Expr("my_func");
-  auto* call = create<ast::CallExpression>(
-      id, ast::ExpressionList{Expr("param1"), Expr("param2")});
+  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
+       ast::DecorationList{});
+  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+
+  auto* call = Call("my_func", "param1", "param2");
+  WrapInFunction(call);
 
   GeneratorImpl& gen = Build();
 
@@ -44,15 +51,19 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitStatement_Call) {
-  auto* id = Expr("my_func");
+  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
+       ast::DecorationList{});
+  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = create<ast::CallStatement>(create<ast::CallExpression>(
-      id, ast::ExpressionList{Expr("param1"), Expr("param2")}));
+  auto* call = Call("my_func", "param1", "param2");
+  auto* stmt = create<ast::CallStatement>(call);
+  WrapInFunction(stmt);
 
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(call)) << gen.error();
+  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
   EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
 }
 
diff --git a/src/writer/wgsl/generator_impl_case_test.cc b/src/writer/wgsl/generator_impl_case_test.cc
index 33d2208..04538cc 100644
--- a/src/writer/wgsl/generator_impl_case_test.cc
+++ b/src/writer/wgsl/generator_impl_case_test.cc
@@ -22,12 +22,11 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Case) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::BreakStatement>(),
-  });
+  auto* body = Block(create<ast::BreakStatement>());
   ast::CaseSelectorList lit;
-  lit.push_back(create<ast::SintLiteral>(ty.i32(), 5));
+  lit.push_back(Literal(5));
   auto* c = create<ast::CaseStatement>(lit, body);
+  WrapInFunction(c);
 
   GeneratorImpl& gen = Build();
 
@@ -41,13 +40,12 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Case_MultipleSelectors) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::BreakStatement>(),
-  });
+  auto* body = Block(create<ast::BreakStatement>());
   ast::CaseSelectorList lit;
-  lit.push_back(create<ast::SintLiteral>(ty.i32(), 5));
-  lit.push_back(create<ast::SintLiteral>(ty.i32(), 6));
+  lit.push_back(Literal(5));
+  lit.push_back(Literal(6));
   auto* c = create<ast::CaseStatement>(lit, body);
+  WrapInFunction(c);
 
   GeneratorImpl& gen = Build();
 
@@ -61,10 +59,9 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Case_Default) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::BreakStatement>(),
-  });
+  auto* body = Block(create<ast::BreakStatement>());
   auto* c = create<ast::CaseStatement>(ast::CaseSelectorList{}, body);
+  WrapInFunction(c);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_cast_test.cc b/src/writer/wgsl/generator_impl_cast_test.cc
index cd62e59..7ecc446 100644
--- a/src/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/writer/wgsl/generator_impl_cast_test.cc
@@ -21,13 +21,24 @@
 
 using WgslGeneratorImplTest = TestHelper;
 
-TEST_F(WgslGeneratorImplTest, EmitExpression_Cast) {
-  auto* cast = Construct<f32>("id");
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
+  auto* cast = Construct<f32>(1);
+  WrapInFunction(cast);
 
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitExpression(cast)) << gen.error();
-  EXPECT_EQ(gen.result(), "f32(id)");
+  EXPECT_EQ(gen.result(), "f32(1)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
+  auto* cast = vec3<f32>(vec3<i32>(1, 2, 3));
+  WrapInFunction(cast);
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitExpression(cast)) << gen.error();
+  EXPECT_EQ(gen.result(), "vec3<f32>(vec3<i32>(1, 2, 3))");
 }
 
 }  // namespace
diff --git a/src/writer/wgsl/generator_impl_constructor_test.cc b/src/writer/wgsl/generator_impl_constructor_test.cc
index 56423c2..65bdafb 100644
--- a/src/writer/wgsl/generator_impl_constructor_test.cc
+++ b/src/writer/wgsl/generator_impl_constructor_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "gmock/gmock.h"
 #include "src/writer/wgsl/test_helper.h"
 
 namespace tint {
@@ -19,112 +20,114 @@
 namespace wgsl {
 namespace {
 
+using ::testing::HasSubstr;
+
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Bool) {
-  auto* expr = Expr(false);
+  WrapInFunction(Expr(false));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "false");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Int) {
-  auto* expr = Expr(-12345);
+  WrapInFunction(Expr(-12345));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "-12345");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_UInt) {
-  auto* expr = Expr(56779u);
+  WrapInFunction(Expr(56779u));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "56779u");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
   // Use a number close to 1<<30 but whose decimal representation ends in 0.
-  auto* expr = Expr(static_cast<float>((1 << 30) - 4));
+  WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "1073741824.0");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("1073741824.0"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
-  auto* expr = Construct<f32>(Expr(-1.2e-5f));
+  WrapInFunction(Construct<f32>(Expr(-1.2e-5f)));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "f32(-0.000012)");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Bool) {
-  auto* expr = Construct<bool>(true);
+  WrapInFunction(Construct<bool>(true));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "bool(true)");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Int) {
-  auto* expr = Construct<i32>(-12345);
+  WrapInFunction(Construct<i32>(-12345));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "i32(-12345)");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("i32(-12345)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Uint) {
-  auto* expr = Construct<u32>(12345u);
+  WrapInFunction(Construct<u32>(12345u));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "u32(12345u)");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
-  auto* expr = vec3<f32>(1.f, 2.f, 3.f);
+  WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), "vec3<f32>(1.0, 2.0, 3.0)");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0, 2.0, 3.0)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
-  auto* expr = Construct(ty.mat2x3<f32>(), vec2<f32>(1.0f, 2.0f),
-                         vec2<f32>(3.0f, 4.0f), vec2<f32>(5.0f, 6.0f));
+  WrapInFunction(
+      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(expr)) << gen.error();
-  EXPECT_EQ(gen.result(),
-            "mat2x3<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0), "
-            "vec2<f32>(5.0, 6.0))");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(), HasSubstr("mat2x3<f32>(vec3<f32>(1.0, 2.0, 3.0), "
+                                      "vec3<f32>(3.0, 4.0, 5.0))"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Array) {
-  auto* expr = 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));
+  WrapInFunction(
+      Construct(ty.array(ty.vec3<f32>(), 3), vec3<f32>(1.0f, 2.0f, 3.0f),
+                vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f)));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitConstructor(expr)) << gen.error();
-  EXPECT_EQ(gen.result(),
-            "array<vec3<f32>, 3>(vec3<f32>(1.0, 2.0, 3.0), "
-            "vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0))");
+  ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
+  EXPECT_THAT(gen.result(),
+              HasSubstr("array<vec3<f32>, 3>(vec3<f32>(1.0, 2.0, 3.0), "
+                        "vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0))"));
 }
 
 }  // namespace
diff --git a/src/writer/wgsl/generator_impl_continue_test.cc b/src/writer/wgsl/generator_impl_continue_test.cc
index b132faa..497acee 100644
--- a/src/writer/wgsl/generator_impl_continue_test.cc
+++ b/src/writer/wgsl/generator_impl_continue_test.cc
@@ -23,6 +23,7 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_Continue) {
   auto* c = create<ast::ContinueStatement>();
+  WrapInFunction(Loop(Block(c)));
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_discard_test.cc b/src/writer/wgsl/generator_impl_discard_test.cc
index 2703061..bb4ebf0 100644
--- a/src/writer/wgsl/generator_impl_discard_test.cc
+++ b/src/writer/wgsl/generator_impl_discard_test.cc
@@ -22,13 +22,14 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Discard) {
-  auto* k = create<ast::DiscardStatement>();
+  auto* stmt = create<ast::DiscardStatement>();
+  WrapInFunction(stmt);
 
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(k)) << gen.error();
+  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
   EXPECT_EQ(gen.result(), "  discard;\n");
 }
 
diff --git a/src/writer/wgsl/generator_impl_entry_point_test.cc b/src/writer/wgsl/generator_impl_entry_point_test.cc
index 886534e..083f37cb 100644
--- a/src/writer/wgsl/generator_impl_entry_point_test.cc
+++ b/src/writer/wgsl/generator_impl_entry_point_test.cc
@@ -59,19 +59,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_EntryPoint_UnusedVariable) {
-  auto* global_unused =
-      Global("global_unused", ty.f32(), ast::StorageClass::kInput);
-  create<ast::VariableDeclStatement>(global_unused);
+  Global("global_unused", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* global_used =
-      Global("global_used", ty.f32(), ast::StorageClass::kInput);
-  create<ast::VariableDeclStatement>(global_used);
+  Global("global_used", ty.f32(), ast::StorageClass::kPrivate);
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
+  Func("main", {}, ty.void_(),
+       {
            create<ast::AssignmentStatement>(Expr("global_used"), Expr(1.f)),
        },
-       ast::DecorationList{
+       {
            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
        });
 
@@ -82,7 +78,7 @@
   ASSERT_TRUE(
       gen.GenerateEntryPoint(tint::ast::PipelineStage::kCompute, "main"))
       << gen.error();
-  EXPECT_EQ(gen.result(), R"(  var<in> global_used : f32;
+  EXPECT_EQ(gen.result(), R"(  var<private> global_used : f32;
 
   [[stage(compute)]]
   fn main() {
@@ -92,39 +88,26 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_EntryPoint_GlobalsInterleaved) {
-  auto* global0 = Global("a0", ty.f32(), ast::StorageClass::kInput);
-  create<ast::VariableDeclStatement>(global0);
+  Global("a0", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* str0 = create<ast::Struct>(ast::StructMemberList{Member("a", ty.i32())},
-                                   ast::DecorationList{});
-  auto* s0 = ty.struct_("S0", str0);
-  AST().AddConstructedType(s0);
+  auto* s0 = Structure("S0", {Member("a", ty.i32())});
 
-  Func("func", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           create<ast::ReturnStatement>(Expr("a0")),
+  Func("func", {}, ty.f32(),
+       {
+           Return("a0"),
+       });
+
+  Global("a1", ty.f32(), ast::StorageClass::kOutput);
+
+  auto* s1 = Structure("S1", {Member("a", ty.i32())});
+
+  Func("main", {}, ty.void_(),
+       {
+           Decl(Var("s0", s0, ast::StorageClass::kFunction)),
+           Decl(Var("s1", s1, ast::StorageClass::kFunction)),
+           create<ast::AssignmentStatement>(Expr("a1"), Call("func")),
        },
-       ast::DecorationList{});
-
-  auto* global1 = Global("a1", ty.f32(), ast::StorageClass::kOutput);
-  create<ast::VariableDeclStatement>(global1);
-
-  auto* str1 = create<ast::Struct>(ast::StructMemberList{Member("a", ty.i32())},
-                                   ast::DecorationList{});
-  auto* s1 = ty.struct_("S1", str1);
-  AST().AddConstructedType(s1);
-
-  auto* call_func = Call("func");
-
-  Func("main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           create<ast::VariableDeclStatement>(
-               Var("s0", s0, ast::StorageClass::kFunction)),
-           create<ast::VariableDeclStatement>(
-               Var("s1", s1, ast::StorageClass::kFunction)),
-           create<ast::AssignmentStatement>(Expr("a1"), Expr(call_func)),
-       },
-       ast::DecorationList{
+       {
            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
        });
 
@@ -135,7 +118,7 @@
   ASSERT_TRUE(
       gen.GenerateEntryPoint(tint::ast::PipelineStage::kCompute, "main"))
       << gen.error();
-  EXPECT_EQ(gen.result(), R"(  var<in> a0 : f32;
+  EXPECT_EQ(gen.result(), R"(  var<private> a0 : f32;
 
   struct S0 {
     a : i32;
diff --git a/src/writer/wgsl/generator_impl_fallthrough_test.cc b/src/writer/wgsl/generator_impl_fallthrough_test.cc
index df2f464..0325256 100644
--- a/src/writer/wgsl/generator_impl_fallthrough_test.cc
+++ b/src/writer/wgsl/generator_impl_fallthrough_test.cc
@@ -23,6 +23,7 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_Fallthrough) {
   auto* f = create<ast::FallthroughStatement>();
+  WrapInFunction(f);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_global_decl_test.cc b/src/writer/wgsl/generator_impl_global_decl_test.cc
index b7e4921..92250da 100644
--- a/src/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/writer/wgsl/generator_impl_global_decl_test.cc
@@ -27,10 +27,9 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
   auto* func_var = Var("a", ty.f32(), ast::StorageClass::kFunction);
-  WrapInFunction(create<ast::VariableDeclStatement>(func_var));
+  WrapInFunction(func_var);
 
-  auto* global_var = Global("a", ty.f32(), ast::StorageClass::kInput);
-  create<ast::VariableDeclStatement>(global_var);
+  Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
   GeneratorImpl& gen = Build();
 
@@ -42,18 +41,14 @@
     var a : f32;
   }
 
-  var<in> a : f32;
+  var<private> a : f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
-  auto* global0 = Global("a0", ty.f32(), ast::StorageClass::kInput);
-  create<ast::VariableDeclStatement>(global0);
+  Global("a0", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* str0 = create<ast::Struct>(ast::StructMemberList{Member("a", ty.i32())},
-                                   ast::DecorationList{});
-  auto* s0 = ty.struct_("S0", str0);
-  AST().AddConstructedType(s0);
+  auto* s0 = Structure("S0", {Member("a", ty.i32())});
 
   Func("func", ast::VariableList{}, ty.f32(),
        ast::StatementList{
@@ -61,23 +56,15 @@
        },
        ast::DecorationList{});
 
-  auto* global1 = Global("a1", ty.f32(), ast::StorageClass::kOutput);
-  create<ast::VariableDeclStatement>(global1);
+  Global("a1", ty.f32(), ast::StorageClass::kOutput);
 
-  auto* str1 = create<ast::Struct>(ast::StructMemberList{Member("a", ty.i32())},
-                                   ast::DecorationList{});
-  auto* s1 = ty.struct_("S1", str1);
-  AST().AddConstructedType(s1);
-
-  auto* call_func = Call("func");
+  auto* s1 = Structure("S1", {Member("a", ty.i32())});
 
   Func("main", ast::VariableList{}, ty.void_(),
        ast::StatementList{
-           create<ast::VariableDeclStatement>(
-               Var("s0", s0, ast::StorageClass::kFunction)),
-           create<ast::VariableDeclStatement>(
-               Var("s1", s1, ast::StorageClass::kFunction)),
-           create<ast::AssignmentStatement>(Expr("a1"), Expr(call_func)),
+           Decl(Var("s0", s0, ast::StorageClass::kFunction)),
+           Decl(Var("s1", s1, ast::StorageClass::kFunction)),
+           create<ast::AssignmentStatement>(Expr("a1"), Call("func")),
        },
        ast::DecorationList{
            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
@@ -88,7 +75,7 @@
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate(nullptr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  var<in> a0 : f32;
+  EXPECT_EQ(gen.result(), R"(  var<private> a0 : f32;
 
   struct S0 {
     a : i32;
diff --git a/src/writer/wgsl/generator_impl_identifier_test.cc b/src/writer/wgsl/generator_impl_identifier_test.cc
index 720d6de..41330a9 100644
--- a/src/writer/wgsl/generator_impl_identifier_test.cc
+++ b/src/writer/wgsl/generator_impl_identifier_test.cc
@@ -23,6 +23,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
   auto* i = Expr("glsl");
+  WrapInFunction(i);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_if_test.cc b/src/writer/wgsl/generator_impl_if_test.cc
index fbbcdbb..a929a69 100644
--- a/src/writer/wgsl/generator_impl_if_test.cc
+++ b/src/writer/wgsl/generator_impl_if_test.cc
@@ -22,11 +22,12 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_If) {
+  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+
   auto* cond = Expr("cond");
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* i = create<ast::IfStatement>(cond, body, ast::ElseStatementList{});
+  auto* body = Block(Return());
+  auto* i = If(cond, body);
+  WrapInFunction(i);
 
   GeneratorImpl& gen = Build();
 
@@ -34,23 +35,24 @@
 
   ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
   EXPECT_EQ(gen.result(), R"(  if (cond) {
-    discard;
+    return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
-  auto* else_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* i = create<ast::IfStatement>(
-      Expr("cond"), body,
-      ast::ElseStatementList{
-          create<ast::ElseStatement>(Expr("else_cond"), else_body)});
+  auto* else_cond = Expr("else_cond");
+  auto* else_body = Block(Return());
+
+  auto* cond = Expr("cond");
+  auto* body = Block(Return());
+  auto* i = If(
+      cond, body,
+      ast::ElseStatementList{create<ast::ElseStatement>(else_cond, else_body)});
+  WrapInFunction(i);
 
   GeneratorImpl& gen = Build();
 
@@ -58,25 +60,24 @@
 
   ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
   EXPECT_EQ(gen.result(), R"(  if (cond) {
-    discard;
+    return;
   } elseif (else_cond) {
-    discard;
+    return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
-  auto* else_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+
+  auto* else_body = Block(Return());
 
   auto* cond = Expr("cond");
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* i = create<ast::IfStatement>(
+  auto* body = Block(Return());
+  auto* i = If(
       cond, body,
       ast::ElseStatementList{create<ast::ElseStatement>(nullptr, else_body)});
+  WrapInFunction(i);
 
   GeneratorImpl& gen = Build();
 
@@ -84,31 +85,31 @@
 
   ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
   EXPECT_EQ(gen.result(), R"(  if (cond) {
-    discard;
+    return;
   } else {
-    discard;
+    return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithMultiple) {
-  auto* else_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_body_2 = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  auto* else_cond = Expr("else_cond");
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* i = create<ast::IfStatement>(
-      Expr("cond"), body,
-      ast::ElseStatementList{
-          create<ast::ElseStatement>(Expr("else_cond"), else_body),
-          create<ast::ElseStatement>(nullptr, else_body_2),
-      });
+  auto* else_body = Block(Return());
+
+  auto* else_body_2 = Block(Return());
+
+  auto* cond = Expr("cond");
+  auto* body = Block(Return());
+  auto* i = If(cond, body,
+               ast::ElseStatementList{
+                   create<ast::ElseStatement>(else_cond, else_body),
+                   create<ast::ElseStatement>(nullptr, else_body_2),
+               });
+  WrapInFunction(i);
 
   GeneratorImpl& gen = Build();
 
@@ -116,11 +117,11 @@
 
   ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
   EXPECT_EQ(gen.result(), R"(  if (cond) {
-    discard;
+    return;
   } elseif (else_cond) {
-    discard;
+    return;
   } else {
-    discard;
+    return;
   }
 )");
 }
diff --git a/src/writer/wgsl/generator_impl_loop_test.cc b/src/writer/wgsl/generator_impl_loop_test.cc
index 768a638..87f8904 100644
--- a/src/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/writer/wgsl/generator_impl_loop_test.cc
@@ -22,10 +22,11 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Loop) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* l = create<ast::LoopStatement>(body, nullptr);
+  auto* body = Block(create<ast::DiscardStatement>());
+  auto* continuing = Block();
+  auto* l = create<ast::LoopStatement>(body, continuing);
+
+  WrapInFunction(l);
 
   GeneratorImpl& gen = Build();
 
@@ -39,14 +40,12 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_LoopWithContinuing) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
-  auto* continuing = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-  });
+  auto* body = Block(create<ast::DiscardStatement>());
+  auto* continuing = Block(Return());
   auto* l = create<ast::LoopStatement>(body, continuing);
 
+  WrapInFunction(l);
+
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
@@ -56,7 +55,7 @@
     discard;
 
     continuing {
-      discard;
+      return;
     }
   }
 )");
diff --git a/src/writer/wgsl/generator_impl_member_accessor_test.cc b/src/writer/wgsl/generator_impl_member_accessor_test.cc
index 16d4a89..1a28011 100644
--- a/src/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -22,10 +22,11 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
-  auto* str = Expr("str");
-  auto* mem = Expr("mem");
+  auto* s = Structure("Data", {Member("mem", ty.f32())});
+  Global("str", s, ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::MemberAccessorExpression>(str, mem);
+  auto* expr = MemberAccessor("str", "mem");
+  WrapInFunction(expr);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_return_test.cc b/src/writer/wgsl/generator_impl_return_test.cc
index 7ba7d594..f261d8e 100644
--- a/src/writer/wgsl/generator_impl_return_test.cc
+++ b/src/writer/wgsl/generator_impl_return_test.cc
@@ -22,7 +22,8 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Return) {
-  auto* r = create<ast::ReturnStatement>();
+  auto* r = Return();
+  WrapInFunction(r);
 
   GeneratorImpl& gen = Build();
 
@@ -33,15 +34,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ReturnWithValue) {
-  auto* expr = Expr("expr");
-  auto* r = create<ast::ReturnStatement>(expr);
+  auto* r = Return(123);
+  Func("f", {}, ty.i32(), {r});
 
   GeneratorImpl& gen = Build();
 
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return expr;\n");
+  EXPECT_EQ(gen.result(), "  return 123;\n");
 }
 
 }  // namespace
diff --git a/src/writer/wgsl/generator_impl_switch_test.cc b/src/writer/wgsl/generator_impl_switch_test.cc
index 9814c58..e90a319 100644
--- a/src/writer/wgsl/generator_impl_switch_test.cc
+++ b/src/writer/wgsl/generator_impl_switch_test.cc
@@ -22,17 +22,15 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Switch) {
-  auto* def_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::BreakStatement>(),
-  });
+  Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+
+  auto* def_body = Block(create<ast::BreakStatement>());
   auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
 
   ast::CaseSelectorList case_val;
-  case_val.push_back(create<ast::SintLiteral>(ty.i32(), 5));
+  case_val.push_back(Literal(5));
 
-  auto* case_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::BreakStatement>(),
-  });
+  auto* case_body = Block(create<ast::BreakStatement>());
 
   auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
 
@@ -42,6 +40,7 @@
 
   auto* cond = Expr("cond");
   auto* s = create<ast::SwitchStatement>(cond, body);
+  WrapInFunction(s);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc
index 287a6a7..bf7e6f1 100644
--- a/src/writer/wgsl/generator_impl_test.cc
+++ b/src/writer/wgsl/generator_impl_test.cc
@@ -46,7 +46,7 @@
 TEST_P(WgslBuiltinConversionTest, Emit) {
   auto params = GetParam();
 
-  auto* var = Global("a", ty.f32(), ast::StorageClass::kInput, nullptr,
+  auto* var = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
                      ast::DecorationList{
                          create<ast::BuiltinDecoration>(params.builtin),
                      });
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc
index fddffcc..85c6cdc 100644
--- a/src/writer/wgsl/generator_impl_type_test.cc
+++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -28,6 +28,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_Alias) {
   auto* alias = ty.alias("alias", ty.f32());
+  AST().AddConstructedType(alias);
 
   GeneratorImpl& gen = Build();
 
@@ -37,6 +38,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array) {
   auto* arr = ty.array<bool, 4>();
+  AST().AddConstructedType(ty.alias("make_type_reachable", arr));
 
   GeneratorImpl& gen = Build();
 
@@ -48,11 +50,12 @@
   auto* s = Structure("S", {Member("a", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
 
-  type::AccessControl a(ast::AccessControl::kReadOnly, s);
+  auto* a = ty.access(ast::AccessControl::kReadOnly, s);
+  AST().AddConstructedType(ty.alias("make_type_reachable", a));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&a)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
   EXPECT_EQ(gen.result(), "[[access(read)]] S");
 }
 
@@ -60,50 +63,55 @@
   auto* s = Structure("S", {Member("a", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
 
-  type::AccessControl a(ast::AccessControl::kReadWrite, s);
+  auto* a = ty.access(ast::AccessControl::kReadWrite, s);
+  AST().AddConstructedType(ty.alias("make_type_reachable", a));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&a)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
   EXPECT_EQ(gen.result(), "[[access(read_write)]] S");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array_Decoration) {
-  type::Array a(ty.bool_(), 4,
-                ast::DecorationList{
-                    create<ast::StrideDecoration>(16u),
-                });
+  auto* a = create<type::Array>(ty.bool_(), 4,
+                                ast::DecorationList{
+                                    create<ast::StrideDecoration>(16u),
+                                });
+  AST().AddConstructedType(ty.alias("make_type_reachable", a));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&a)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
   EXPECT_EQ(gen.result(), "[[stride(16)]] array<bool, 4>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array_MultipleDecorations) {
-  type::Array a(ty.bool_(), 4,
-                ast::DecorationList{
-                    create<ast::StrideDecoration>(16u),
-                    create<ast::StrideDecoration>(32u),
-                });
+  auto* a = create<type::Array>(ty.bool_(), 4,
+                                ast::DecorationList{
+                                    create<ast::StrideDecoration>(16u),
+                                    create<ast::StrideDecoration>(32u),
+                                });
+  AST().AddConstructedType(ty.alias("make_type_reachable", a));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&a)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
   EXPECT_EQ(gen.result(), "[[stride(16)]] [[stride(32)]] array<bool, 4>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_RuntimeArray) {
-  type::Array a(ty.bool_(), 0, ast::DecorationList{});
+  auto* a = create<type::Array>(ty.bool_(), 0, ast::DecorationList{});
+  AST().AddConstructedType(ty.alias("make_type_reachable", a));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&a)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
   EXPECT_EQ(gen.result(), "array<bool>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Bool) {
   auto* bool_ = ty.bool_();
+  AST().AddConstructedType(ty.alias("make_type_reachable", bool_));
 
   GeneratorImpl& gen = Build();
 
@@ -113,6 +121,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_F32) {
   auto* f32 = ty.f32();
+  AST().AddConstructedType(ty.alias("make_type_reachable", f32));
 
   GeneratorImpl& gen = Build();
 
@@ -122,6 +131,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_I32) {
   auto* i32 = ty.i32();
+  AST().AddConstructedType(ty.alias("make_type_reachable", i32));
 
   GeneratorImpl& gen = Build();
 
@@ -131,6 +141,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
   auto* mat2x3 = ty.mat2x3<f32>();
+  AST().AddConstructedType(ty.alias("make_type_reachable", mat2x3));
 
   GeneratorImpl& gen = Build();
 
@@ -139,11 +150,12 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
-  type::Pointer p(ty.f32(), ast::StorageClass::kWorkgroup);
+  auto* p = create<type::Pointer>(ty.f32(), ast::StorageClass::kWorkgroup);
+  AST().AddConstructedType(ty.alias("make_type_reachable", p));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&p)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(p)) << gen.error();
   EXPECT_EQ(gen.result(), "ptr<workgroup, f32>");
 }
 
@@ -283,6 +295,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_U32) {
   auto* u32 = ty.u32();
+  AST().AddConstructedType(ty.alias("make_type_reachable", u32));
 
   GeneratorImpl& gen = Build();
 
@@ -292,6 +305,7 @@
 
 TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
   auto* vec3 = ty.vec3<f32>();
+  AST().AddConstructedType(ty.alias("make_type_reachable", vec3));
 
   GeneratorImpl& gen = Build();
 
@@ -299,15 +313,6 @@
   EXPECT_EQ(gen.result(), "vec3<f32>");
 }
 
-TEST_F(WgslGeneratorImplTest, EmitType_Void) {
-  auto* void_ = ty.void_();
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.EmitType(void_)) << gen.error();
-  EXPECT_EQ(gen.result(), "void");
-}
-
 struct TextureData {
   type::TextureDimension dim;
   const char* name;
@@ -321,11 +326,12 @@
 TEST_P(WgslGenerator_DepthTextureTest, EmitType_DepthTexture) {
   auto param = GetParam();
 
-  type::DepthTexture d(param.dim);
+  auto* d = create<type::DepthTexture>(param.dim);
+  AST().AddConstructedType(ty.alias("make_type_reachable", d));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&d)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(d)) << gen.error();
   EXPECT_EQ(gen.result(), param.name);
 }
 INSTANTIATE_TEST_SUITE_P(
@@ -342,33 +348,36 @@
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_F32) {
   auto param = GetParam();
 
-  type::SampledTexture t(param.dim, ty.f32());
+  auto* t = create<type::SampledTexture>(param.dim, ty.f32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<f32>");
 }
 
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_I32) {
   auto param = GetParam();
 
-  type::SampledTexture t(param.dim, ty.i32());
+  auto* t = create<type::SampledTexture>(param.dim, ty.i32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<i32>");
 }
 
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_U32) {
   auto param = GetParam();
 
-  type::SampledTexture t(param.dim, ty.u32());
+  auto* t = create<type::SampledTexture>(param.dim, ty.u32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<u32>");
 }
 INSTANTIATE_TEST_SUITE_P(
@@ -386,33 +395,36 @@
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_F32) {
   auto param = GetParam();
 
-  type::MultisampledTexture t(param.dim, ty.f32());
+  auto* t = create<type::MultisampledTexture>(param.dim, ty.f32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<f32>");
 }
 
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_I32) {
   auto param = GetParam();
 
-  type::MultisampledTexture t(param.dim, ty.i32());
+  auto* t = create<type::MultisampledTexture>(param.dim, ty.i32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<i32>");
 }
 
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_U32) {
   auto param = GetParam();
 
-  type::MultisampledTexture t(param.dim, ty.u32());
+  auto* t = create<type::MultisampledTexture>(param.dim, ty.u32());
+  AST().AddConstructedType(ty.alias("make_type_reachable", t));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&t)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), std::string(param.name) + "<u32>");
 }
 INSTANTIATE_TEST_SUITE_P(WgslGeneratorImplTest,
@@ -437,7 +449,7 @@
 
   auto* subtype = type::StorageTexture::SubtypeFor(param.fmt, Types());
   auto* t = create<type::StorageTexture>(param.dim, param.fmt, subtype);
-  auto* ac = create<type::AccessControl>(param.access, t);
+  auto* ac = ty.access(param.access, t);
 
   GeneratorImpl& gen = Build();
 
@@ -540,20 +552,22 @@
         ImageFormatData{type::ImageFormat::kRgba32Float, "rgba32float"}));
 
 TEST_F(WgslGeneratorImplTest, EmitType_Sampler) {
-  type::Sampler sampler(type::SamplerKind::kSampler);
+  auto* sampler = create<type::Sampler>(type::SamplerKind::kSampler);
+  AST().AddConstructedType(ty.alias("make_type_reachable", sampler));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&sampler)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(sampler)) << gen.error();
   EXPECT_EQ(gen.result(), "sampler");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_SamplerComparison) {
-  type::Sampler sampler(type::SamplerKind::kComparisonSampler);
+  auto* sampler = create<type::Sampler>(type::SamplerKind::kComparisonSampler);
+  AST().AddConstructedType(ty.alias("make_type_reachable", sampler));
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(&sampler)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(sampler)) << gen.error();
   EXPECT_EQ(gen.result(), "sampler_comparison");
 }
 
diff --git a/src/writer/wgsl/generator_impl_unary_op_test.cc b/src/writer/wgsl/generator_impl_unary_op_test.cc
index f466282..40df2bc 100644
--- a/src/writer/wgsl/generator_impl_unary_op_test.cc
+++ b/src/writer/wgsl/generator_impl_unary_op_test.cc
@@ -31,8 +31,13 @@
 TEST_P(WgslUnaryOpTest, Emit) {
   auto params = GetParam();
 
-  auto* expr = Expr("expr");
-  auto* op = create<ast::UnaryOpExpression>(params.op, expr);
+  auto* type = (params.op == ast::UnaryOp::kNot)
+                   ? static_cast<type::Type*>(ty.bool_())
+                   : static_cast<type::Type*>(ty.i32());
+  Global("expr", type, ast::StorageClass::kPrivate);
+
+  auto* op = create<ast::UnaryOpExpression>(params.op, Expr("expr"));
+  WrapInFunction(op);
 
   GeneratorImpl& gen = Build();
 
diff --git a/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index 27fa34f..6ff5880 100644
--- a/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -23,24 +23,6 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement) {
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kInput);
-
-  auto* stmt = create<ast::VariableDeclStatement>(var);
-  WrapInFunction(stmt);
-
-  GeneratorImpl& gen = Build();
-
-  gen.increment_indent();
-
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  var<in> a : f32;\n");
-}
-
-TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Function) {
-  // Variable declarations with Function storage class don't mention their
-  // storage class.  Rely on defaulting.
-  // https://github.com/gpuweb/gpuweb/issues/654
-
   auto* var = Var("a", ty.f32(), ast::StorageClass::kFunction);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
@@ -54,20 +36,6 @@
   EXPECT_EQ(gen.result(), "  var a : f32;\n");
 }
 
-TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kPrivate);
-
-  auto* stmt = create<ast::VariableDeclStatement>(var);
-  WrapInFunction(stmt);
-
-  GeneratorImpl& gen = Build();
-
-  gen.increment_indent();
-
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  var<private> a : f32;\n");
-}
-
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_InferredType) {
   auto* var = Var("a", nullptr, ast::StorageClass::kFunction, Expr(123));
 
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index cf1bed0..5af5c6b 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -23,27 +23,27 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitVariable) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kInput);
+  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(var<in> a : f32;
+  EXPECT_EQ(gen.result(), R"(var<private> a : f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kInput);
+  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(var<in> a : f32;
+  EXPECT_EQ(gen.result(), R"(var<private> a : f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kInput, nullptr,
+  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
                    ast::DecorationList{
                        create<ast::LocationDecoration>(2),
                    });
@@ -51,12 +51,12 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(gen.result(), R"([[location(2)]] var<in> a : f32;
+  EXPECT_EQ(gen.result(), R"([[location(2)]] var<private> a : f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated_Multiple) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kInput, nullptr,
+  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
                    ast::DecorationList{
                        create<ast::BuiltinDecoration>(ast::Builtin::kPosition),
                        create<ast::BindingDecoration>(0),
@@ -70,17 +70,17 @@
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
   EXPECT_EQ(
       gen.result(),
-      R"([[builtin(position), binding(0), group(1), location(2), constant_id(42)]] var<in> a : f32;
+      R"([[builtin(position), binding(0), group(1), location(2), constant_id(42)]] var<private> a : f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kInput, Expr(1.0f));
+  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(1.0f));
 
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(var<in> a : f32 = 1.0;
+  EXPECT_EQ(gen.result(), R"(var<private> a : f32 = 1.0;
 )");
 }