Add helper for function creation.

This CL adds a Func helper to the ast builder class. The helper is then
used through the various files to simplify function creation.

Change-Id: Ie93777586e9311d82cff5932dfba2c4ca763ae08
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35823
Commit-Queue: dan sinclair <dsinclair@chromium.org>
Reviewed-by: Ben Clayton <bclayton@google.com>
diff --git a/src/ast/builder.h b/src/ast/builder.h
index a450a6e..807dba2 100644
--- a/src/ast/builder.h
+++ b/src/ast/builder.h
@@ -581,6 +581,42 @@
     return mod->create<StructMemberOffsetDecoration>(source_, val);
   }
 
+  /// Creates a Function
+  /// @param source the source information
+  /// @param name the function name
+  /// @param params the function parameters
+  /// @param type the function return type
+  /// @param body the function body
+  /// @param decorations the function decorations
+  /// @returns the function pointer
+  Function* Func(Source source,
+                 std::string name,
+                 ast::VariableList params,
+                 type::Type* type,
+                 ast::StatementList body,
+                 ast::FunctionDecorationList decorations) {
+    return mod->create<ast::Function>(
+        source, mod->RegisterSymbol(name), name, params, type,
+        create<ast::BlockStatement>(body), decorations);
+  }
+
+  /// Creates a Function
+  /// @param name the function name
+  /// @param params the function parameters
+  /// @param type the function return type
+  /// @param body the function body
+  /// @param decorations the function decorations
+  /// @returns the function pointer
+  Function* Func(std::string name,
+                 ast::VariableList params,
+                 type::Type* type,
+                 ast::StatementList body,
+                 ast::FunctionDecorationList decorations) {
+    return create<ast::Function>(mod->RegisterSymbol(name), name, params, type,
+                                 create<ast::BlockStatement>(body),
+                                 decorations);
+  }
+
   /// Creates a StructMember
   /// @param name the struct member name
   /// @param type the struct member type
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index ec31937..fe18df0 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -81,14 +81,10 @@
   /// @returns a function object
   ast::Function* MakeEmptyBodyFunction(
       std::string name,
-      ast::FunctionDecorationList decorations = {}) {
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(name), name,
-                                 ast::VariableList(), ty.void_, body,
-                                 decorations);
+      ast::FunctionDecorationList decorations) {
+    return Func(name, ast::VariableList(), ty.void_,
+                ast::StatementList{create<ast::ReturnStatement>(Source{})},
+                decorations);
   }
 
   /// Generates a function that calls another
@@ -99,19 +95,18 @@
   ast::Function* MakeCallerBodyFunction(
       std::string caller,
       std::string callee,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     auto* ident_expr = create<ast::IdentifierExpression>(
         Source{}, mod->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::CallStatement>(Source{}, call_expr),
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(caller), caller,
-                                 ast::VariableList(), ty.void_, body,
-                                 decorations);
+
+    return Func(caller, ast::VariableList(), ty.void_,
+                ast::StatementList{
+                    create<ast::CallStatement>(Source{}, call_expr),
+                    create<ast::ReturnStatement>(Source{}),
+                },
+                decorations);
   }
 
   /// Add In/Out variables to the global variables
@@ -152,7 +147,7 @@
   ast::Function* MakeInOutVariableBodyFunction(
       std::string name,
       std::vector<std::tuple<std::string, std::string>> inout_vars,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     ast::StatementList stmts;
     for (auto inout : inout_vars) {
       std::string in, out;
@@ -165,10 +160,7 @@
                                             in)));
     }
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(name), name,
-                                 ast::VariableList(), ty.void_, body,
-                                 decorations);
+    return Func(name, ast::VariableList(), ty.void_, stmts, decorations);
   }
 
   /// Generates a function that references in/out variables and calls another
@@ -183,7 +175,7 @@
       std::string caller,
       std::string callee,
       std::vector<std::tuple<std::string, std::string>> inout_vars,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     ast::StatementList stmts;
     for (auto inout : inout_vars) {
       std::string in, out;
@@ -201,10 +193,8 @@
                                                   ast::ExpressionList());
     stmts.emplace_back(create<ast::CallStatement>(Source{}, call_expr));
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(caller), caller,
-                                 ast::VariableList(), ty.void_, body,
-                                 decorations);
+
+    return Func(caller, ast::VariableList(), ty.void_, stmts, decorations);
   }
 
   /// Add a Constant ID to the global variables.
@@ -467,10 +457,9 @@
     }
 
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(func_name),
-                                 func_name, ast::VariableList(), ty.void_, body,
-                                 ast::FunctionDecorationList{});
+
+    return Func(func_name, ast::VariableList(), ty.void_, stmts,
+                ast::FunctionDecorationList{});
   }
 
   /// Adds a regular sampler variable to the module
@@ -584,7 +573,7 @@
       const std::string& sampler_name,
       const std::string& coords_name,
       ast::type::Type* base_type,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     std::string result_name = "sampler_result";
 
     ast::StatementList stmts;
@@ -619,10 +608,7 @@
         call_expr));
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
 
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(func_name),
-                                 func_name, ast::VariableList(), ty.void_, body,
-                                 decorations);
+    return Func(func_name, ast::VariableList(), ty.void_, stmts, decorations);
   }
 
   /// Generates a function that references a specific sampler variable
@@ -641,7 +627,7 @@
       const std::string& coords_name,
       const std::string& array_index,
       ast::type::Type* base_type,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     std::string result_name = "sampler_result";
 
     ast::StatementList stmts;
@@ -679,10 +665,7 @@
         call_expr));
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
 
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(func_name),
-                                 func_name, ast::VariableList(), ty.void_, body,
-                                 decorations);
+    return Func(func_name, ast::VariableList(), ty.void_, stmts, decorations);
   }
 
   /// Generates a function that references a specific comparison sampler
@@ -702,7 +685,7 @@
       const std::string& coords_name,
       const std::string& depth_name,
       ast::type::Type* base_type,
-      ast::FunctionDecorationList decorations = {}) {
+      ast::FunctionDecorationList decorations) {
     std::string result_name = "sampler_result";
 
     ast::StatementList stmts;
@@ -741,10 +724,7 @@
         call_expr));
     stmts.emplace_back(create<ast::ReturnStatement>(Source{}));
 
-    auto* body = create<ast::BlockStatement>(Source{}, stmts);
-    return create<ast::Function>(Source{}, mod->RegisterSymbol(func_name),
-                                 func_name, ast::VariableList(), ty.void_, body,
-                                 decorations);
+    return Func(func_name, ast::VariableList(), ty.void_, stmts, decorations);
   }
 
   /// Gets an appropriate type for the data in a given texture type.
@@ -876,7 +856,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
-  mod->AddFunction(MakeEmptyBodyFunction("foo"));
+  mod->AddFunction(MakeEmptyBodyFunction("foo", {}));
 
   auto result = inspector()->GetEntryPoints();
   ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
@@ -933,7 +913,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
-  auto* func = MakeEmptyBodyFunction("func");
+  auto* func = MakeEmptyBodyFunction("func", {});
   mod->AddFunction(func);
 
   auto* foo = MakeCallerBodyFunction(
@@ -1004,7 +984,7 @@
 }
 
 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
-  auto* func = MakeEmptyBodyFunction("func");
+  auto* func = MakeEmptyBodyFunction("func", {});
   mod->AddFunction(func);
 
   auto* foo = MakeCallerBodyFunction(
@@ -1048,7 +1028,8 @@
 TEST_F(InspectorGetEntryPointTest, FunctionInOutVariables) {
   AddInOutVariables({{"in_var", "out_var"}});
 
-  auto* func = MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
+  auto* func =
+      MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
   mod->AddFunction(func);
 
   auto* foo = MakeCallerBodyFunction(
@@ -1074,7 +1055,8 @@
 TEST_F(InspectorGetEntryPointTest, RepeatedInOutVariables) {
   AddInOutVariables({{"in_var", "out_var"}});
 
-  auto* func = MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}});
+  auto* func =
+      MakeInOutVariableBodyFunction("func", {{"in_var", "out_var"}}, {});
   mod->AddFunction(func);
 
   auto* foo = MakeInOutVariableCallerBodyFunction(
@@ -1126,7 +1108,7 @@
   AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
 
   auto* func = MakeInOutVariableBodyFunction(
-      "func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}});
+      "func", {{"in_var", "out_var"}, {"in2_var", "out2_var"}}, {});
   mod->AddFunction(func);
 
   auto* foo = MakeCallerBodyFunction(
@@ -1195,7 +1177,8 @@
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsSharedInOutVariables) {
   AddInOutVariables({{"in_var", "out_var"}, {"in2_var", "out2_var"}});
 
-  auto* func = MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}});
+  auto* func =
+      MakeInOutVariableBodyFunction("func", {{"in2_var", "out2_var"}}, {});
   mod->AddFunction(func);
 
   auto* foo = MakeInOutVariableCallerBodyFunction(
@@ -1250,7 +1233,7 @@
 // TODO(rharrison): Reenable once GetRemappedNameForEntryPoint isn't a pass
 // through
 TEST_F(InspectorGetRemappedNameForEntryPointTest, DISABLED_NoEntryPoints) {
-  mod->AddFunction(MakeEmptyBodyFunction("foo"));
+  mod->AddFunction(MakeEmptyBodyFunction("foo", {}));
 
   auto result = inspector()->GetRemappedNameForEntryPoint("foo");
   ASSERT_TRUE(inspector()->has_error());
@@ -1542,20 +1525,15 @@
                                                   ast::ExpressionList());
     return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    FuncCall("ub_foo_func"),
-                    FuncCall("ub_bar_func"),
-                    FuncCall("ub_baz_func"),
-                    create<ast::ReturnStatement>(Source{}),
-                });
 
-  ast::Function* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_func"), "ep_func", ast::VariableList(),
-      ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
-      });
+  ast::Function* func =
+      Func("ep_func", ast::VariableList(), ty.void_,
+           ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
+                              FuncCall("ub_baz_func"),
+                              create<ast::ReturnStatement>()},
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   ASSERT_TRUE(td()->Determine()) << td()->error();
@@ -1690,17 +1668,15 @@
                                                   ast::ExpressionList());
     return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    FuncCall("sb_foo_func"),
-                    FuncCall("sb_bar_func"),
-                    FuncCall("sb_baz_func"),
-                    create<ast::ReturnStatement>(Source{}),
-                });
 
-  ast::Function* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_func"), "ep_func", ast::VariableList(),
-      ty.void_, body,
+  ast::Function* func = Func(
+      "ep_func", ast::VariableList(), ty.void_,
+      ast::StatementList{
+          FuncCall("sb_foo_func"),
+          FuncCall("sb_bar_func"),
+          FuncCall("sb_baz_func"),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
       });
@@ -1865,17 +1841,15 @@
                                                   ast::ExpressionList());
     return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    FuncCall("sb_foo_func"),
-                    FuncCall("sb_bar_func"),
-                    FuncCall("sb_baz_func"),
-                    create<ast::ReturnStatement>(Source{}),
-                });
 
-  ast::Function* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_func"), "ep_func", ast::VariableList(),
-      ty.void_, body,
+  ast::Function* func = Func(
+      "ep_func", ast::VariableList(), ty.void_,
+      ast::StatementList{
+          FuncCall("sb_foo_func"),
+          FuncCall("sb_bar_func"),
+          FuncCall("sb_baz_func"),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
       });
@@ -2036,7 +2010,7 @@
   AddGlobalVariable("foo_coords", ty.f32);
 
   auto* foo_func = MakeSamplerReferenceBodyFunction(
-      "foo_func", "foo_texture", "foo_sampler", "foo_coords", ty.f32);
+      "foo_func", "foo_texture", "foo_sampler", "foo_coords", ty.f32, {});
   mod->AddFunction(foo_func);
 
   auto* ep_func = MakeCallerBodyFunction(
@@ -2150,7 +2124,7 @@
 
   auto* foo_func = MakeComparisonSamplerReferenceBodyFunction(
       "foo_func", "foo_texture", "foo_sampler", "foo_coords", "foo_depth",
-      ty.f32);
+      ty.f32, {});
   mod->AddFunction(foo_func);
 
   auto* ep_func = MakeCallerBodyFunction(
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index 1f33e00..a3c148f 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -93,10 +93,8 @@
 struct ModuleBuilder : public ast::BuilderWithModule {
   ast::Module Module() {
     Build();
-    auto* body = create<ast::BlockStatement>(statements);
-    mod->AddFunction(create<ast::Function>(mod->RegisterSymbol("func"), "func",
-                                           ast::VariableList{}, ty.void_, body,
-                                           ast::FunctionDecorationList{}));
+    mod->AddFunction(Func("func", ast::VariableList{}, ty.void_, statements,
+                          ast::FunctionDecorationList{}));
     return std::move(*mod);
   }
 
diff --git a/src/transform/emit_vertex_point_size_test.cc b/src/transform/emit_vertex_point_size_test.cc
index 347dab3..c3c5f70 100644
--- a/src/transform/emit_vertex_point_size_test.cc
+++ b/src/transform/emit_vertex_point_size_test.cc
@@ -53,31 +53,25 @@
 TEST_F(EmitVertexPointSizeTest, VertexStageBasic) {
   struct Builder : ModuleBuilder {
     void Build() override {
-      auto* block = create<ast::BlockStatement>(ast::StatementList{
-          create<ast::VariableDeclStatement>(
-              Var("builtin_assignments_should_happen_before_this",
-                  tint::ast::StorageClass::kFunction, ty.f32)),
-      });
+      mod->AddFunction(Func("non_entry_a", ast::VariableList{}, ty.void_,
+                            ast::StatementList{},
+                            ast::FunctionDecorationList{}));
 
-      auto a_sym = mod->RegisterSymbol("non_entry_a");
-      mod->AddFunction(create<ast::Function>(
-          a_sym, "non_entry_a", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
-          ast::FunctionDecorationList{}));
-
-      auto entry_sym = mod->RegisterSymbol("entry");
-      auto* entry = create<ast::Function>(
-          entry_sym, "entry", ast::VariableList{}, ty.void_, block,
-          ast::FunctionDecorationList{
-              create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-          });
+      auto* entry =
+          Func("entry", ast::VariableList{}, ty.void_,
+               ast::StatementList{
+                   create<ast::VariableDeclStatement>(
+                       Var("builtin_assignments_should_happen_before_this",
+                           tint::ast::StorageClass::kFunction, ty.f32)),
+               },
+               ast::FunctionDecorationList{
+                   create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+               });
       mod->AddFunction(entry);
 
-      auto b_sym = mod->RegisterSymbol("non_entry_b");
-      mod->AddFunction(create<ast::Function>(
-          b_sym, "non_entry_b", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
-          ast::FunctionDecorationList{}));
+      mod->AddFunction(Func("non_entry_b", ast::VariableList{}, ty.void_,
+                            ast::StatementList{},
+                            ast::FunctionDecorationList{}));
     }
   };
 
@@ -127,25 +121,19 @@
 TEST_F(EmitVertexPointSizeTest, VertexStageEmpty) {
   struct Builder : ModuleBuilder {
     void Build() override {
-      auto a_sym = mod->RegisterSymbol("non_entry_a");
-      mod->AddFunction(create<ast::Function>(
-          a_sym, "non_entry_a", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
-          ast::FunctionDecorationList{}));
+      mod->AddFunction(Func("non_entry_a", ast::VariableList{}, ty.void_,
+                            ast::StatementList{},
+                            ast::FunctionDecorationList{}));
 
-      auto entry_sym = mod->RegisterSymbol("entry");
-      mod->AddFunction(create<ast::Function>(
-          entry_sym, "entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
-          ast::FunctionDecorationList{
-              create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-          }));
+      mod->AddFunction(
+          Func("entry", ast::VariableList{}, ty.void_, ast::StatementList{},
+               ast::FunctionDecorationList{
+                   create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+               }));
 
-      auto b_sym = mod->RegisterSymbol("non_entry_b");
-      mod->AddFunction(create<ast::Function>(
-          b_sym, "non_entry_b", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
-          ast::FunctionDecorationList{}));
+      mod->AddFunction(Func("non_entry_b", ast::VariableList{}, ty.void_,
+                            ast::StatementList{},
+                            ast::FunctionDecorationList{}));
     }
   };
 
@@ -188,19 +176,15 @@
 TEST_F(EmitVertexPointSizeTest, NonVertexStage) {
   struct Builder : ModuleBuilder {
     void Build() override {
-      auto frag_sym = mod->RegisterSymbol("fragment_entry");
-      auto* fragment_entry = create<ast::Function>(
-          frag_sym, "fragment_entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
+      auto* fragment_entry = Func(
+          "fragment_entry", ast::VariableList{}, ty.void_, ast::StatementList{},
           ast::FunctionDecorationList{
               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
           });
       mod->AddFunction(fragment_entry);
 
-      auto comp_sym = mod->RegisterSymbol("compute_entry");
-      auto* compute_entry = create<ast::Function>(
-          comp_sym, "compute_entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(ast::StatementList{}),
+      auto* compute_entry = Func(
+          "compute_entry", ast::VariableList{}, ty.void_, ast::StatementList{},
           ast::FunctionDecorationList{
               create<ast::StageDecoration>(ast::PipelineStage::kCompute),
           });
diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc
index 886ae64..5538577 100644
--- a/src/transform/first_index_offset_test.cc
+++ b/src/transform/first_index_offset_test.cc
@@ -58,9 +58,8 @@
 
   ast::Function* AddFunction(const std::string& name,
                              ast::StatementList stmts) {
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol(name), name, ast::VariableList{}, ty.u32,
-        create<ast::BlockStatement>(stmts), ast::FunctionDecorationList{});
+    auto* func = Func(name, ast::VariableList{}, ty.u32, stmts,
+                      ast::FunctionDecorationList{});
     mod->AddFunction(func);
     return func;
   }
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index 3a7c2f0..61a968e 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -46,12 +46,10 @@
 
   // Create basic module with an entry point and vertex function
   void InitBasicModule() {
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol("main"), "main", ast::VariableList{},
-        mod->create<ast::type::Void>(),
-        create<ast::BlockStatement>(ast::StatementList{}),
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
+    auto* func =
+        Func("main", ast::VariableList{}, ty.void_, ast::StatementList{},
+             ast::FunctionDecorationList{
+                 create<ast::StageDecoration>(ast::PipelineStage::kVertex)});
     mod->AddFunction(func);
   }
 
@@ -115,13 +113,11 @@
 }
 
 TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", ast::VariableList{},
-      mod->create<ast::type::Void>(),
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.void_, ast::StatementList{},
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
   mod->AddFunction(func);
 
   InitTransform({});
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index a3abb7f..f352140 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -290,10 +290,8 @@
 
 TEST_F(TypeDeterminerTest, Stmt_Call) {
   ast::VariableList params;
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", params, ty.f32,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -314,22 +312,20 @@
   SetSource(Source::Location{12, 34});
   auto* call_expr = Call("func");
   ast::VariableList params0;
-  auto* main_body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::CallStatement>(call_expr),
-      create<ast::ReturnStatement>(),
-  });
 
-  auto* func_main =
-      create<ast::Function>(mod->RegisterSymbol("main"), "main", params0,
-                            ty.f32, main_body, ast::FunctionDecorationList{});
+  auto* func_main = Func("main", params0, ty.f32,
+                         ast::StatementList{
+                             create<ast::CallStatement>(call_expr),
+                             create<ast::ReturnStatement>(),
+                         },
+                         ast::FunctionDecorationList{});
   mod->AddFunction(func_main);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* func = Func("func", params0, ty.f32,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_FALSE(td()->Determine()) << td()->error();
@@ -481,10 +477,8 @@
 
 TEST_F(TypeDeterminerTest, Expr_Call) {
   ast::VariableList params;
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", params, ty.f32,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -498,10 +492,8 @@
 
 TEST_F(TypeDeterminerTest, Expr_Call_WithParams) {
   ast::VariableList params;
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", params, ty.f32,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", params, ty.f32, ast::StatementList{},
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -589,13 +581,12 @@
 
   auto* var = Const("my_var", ast::StorageClass::kNone, ty.f32);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::AssignmentStatement>(my_var, Expr("my_var")),
-  });
-  auto* f = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                  ast::VariableList{}, ty.f32, body,
-                                  ast::FunctionDecorationList{});
+  auto* f = Func("my_func", ast::VariableList{}, ty.f32,
+                 ast::StatementList{
+                     create<ast::VariableDeclStatement>(var),
+                     create<ast::AssignmentStatement>(my_var, Expr("my_var")),
+                 },
+                 ast::FunctionDecorationList{});
 
   EXPECT_TRUE(td()->DetermineFunction(f));
 
@@ -606,15 +597,13 @@
 TEST_F(TypeDeterminerTest, Expr_Identifier_FunctionVariable) {
   auto* my_var = Expr("my_var");
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(
-          Var("my_var", ast::StorageClass::kNone, ty.f32)),
-      create<ast::AssignmentStatement>(my_var, Expr("my_var")),
-  });
-
-  auto* f = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                  ast::VariableList{}, ty.f32, body,
-                                  ast::FunctionDecorationList{});
+  auto* f = Func("my_func", ast::VariableList{}, ty.f32,
+                 ast::StatementList{
+                     create<ast::VariableDeclStatement>(
+                         Var("my_var", ast::StorageClass::kNone, ty.f32)),
+                     create<ast::AssignmentStatement>(my_var, Expr("my_var")),
+                 },
+                 ast::FunctionDecorationList{});
 
   EXPECT_TRUE(td()->DetermineFunction(f));
 
@@ -631,17 +620,13 @@
 
   auto* my_var = Expr("my_var");
 
-  auto* body = create<ast::BlockStatement>(
-
-      ast::StatementList{
-          create<ast::VariableDeclStatement>(
-              Var("my_var", ast::StorageClass::kNone, &ptr)),
-          create<ast::AssignmentStatement>(my_var, Expr("my_var")),
-      });
-
-  auto* f = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                  ast::VariableList{}, ty.f32, body,
-                                  ast::FunctionDecorationList{});
+  auto* f = Func("my_func", ast::VariableList{}, ty.f32,
+                 ast::StatementList{
+                     create<ast::VariableDeclStatement>(
+                         Var("my_var", ast::StorageClass::kNone, &ptr)),
+                     create<ast::AssignmentStatement>(my_var, Expr("my_var")),
+                 },
+                 ast::FunctionDecorationList{});
 
   EXPECT_TRUE(td()->DetermineFunction(f));
 
@@ -654,10 +639,8 @@
 }
 
 TEST_F(TypeDeterminerTest, Expr_Identifier_Function) {
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.f32,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.f32,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -687,15 +670,15 @@
   mod->AddGlobalVariable(wg_var);
   mod->AddGlobalVariable(priv_var);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("out_var"), Expr("in_var")),
-      create<ast::AssignmentStatement>(Expr("wg_var"), Expr("wg_var")),
-      create<ast::AssignmentStatement>(Expr("sb_var"), Expr("sb_var")),
-      create<ast::AssignmentStatement>(Expr("priv_var"), Expr("priv_var")),
-  });
-  auto* func = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                     ast::VariableList{}, ty.f32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func(
+      "my_func", ast::VariableList{}, ty.f32,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("out_var"), Expr("in_var")),
+          create<ast::AssignmentStatement>(Expr("wg_var"), Expr("wg_var")),
+          create<ast::AssignmentStatement>(Expr("sb_var"), Expr("sb_var")),
+          create<ast::AssignmentStatement>(Expr("priv_var"), Expr("priv_var")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -724,25 +707,24 @@
   mod->AddGlobalVariable(wg_var);
   mod->AddGlobalVariable(priv_var);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("out_var"), Expr("in_var")),
-      create<ast::AssignmentStatement>(Expr("wg_var"), Expr("wg_var")),
-      create<ast::AssignmentStatement>(Expr("sb_var"), Expr("sb_var")),
-      create<ast::AssignmentStatement>(Expr("priv_var"), Expr("priv_var")),
-  });
-  auto* func = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                     ast::VariableList{}, ty.f32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func(
+      "my_func", ast::VariableList{}, ty.f32,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("out_var"), Expr("in_var")),
+          create<ast::AssignmentStatement>(Expr("wg_var"), Expr("wg_var")),
+          create<ast::AssignmentStatement>(Expr("sb_var"), Expr("sb_var")),
+          create<ast::AssignmentStatement>(Expr("priv_var"), Expr("priv_var")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("out_var"), Call("my_func")),
-  });
-
-  auto* func2 = create<ast::Function>(mod->RegisterSymbol("func"), "func",
-                                      ast::VariableList{}, ty.f32, body,
-                                      ast::FunctionDecorationList{});
+  auto* func2 = Func(
+      "func", ast::VariableList{}, ty.f32,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("out_var"), Call("my_func")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(func2);
 
@@ -761,17 +743,15 @@
 TEST_F(TypeDeterminerTest, Function_NotRegisterFunctionVariable) {
   auto* var = Var("in_var", ast::StorageClass::kFunction, ty.f32);
 
-  auto* body = create<ast::BlockStatement>(
-
-      ast::StatementList{
-          create<ast::VariableDeclStatement>(var),
-          create<ast::AssignmentStatement>(
-              Expr("var"), create<ast::ScalarConstructorExpression>(
-                               create<ast::FloatLiteral>(ty.f32, 1.f))),
-      });
-  auto* func = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                     ast::VariableList{}, ty.f32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func =
+      Func("my_func", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::AssignmentStatement>(
+                   Expr("var"), create<ast::ScalarConstructorExpression>(
+                                    create<ast::FloatLiteral>(ty.f32, 1.f))),
+           },
+           ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -1742,10 +1722,8 @@
   auto* var = Var("var", ast::StorageClass::kNone, ty.i32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
-  auto* body = create<ast::BlockStatement>(ast::StatementList{stmt});
-  auto* func = create<ast::Function>(mod->RegisterSymbol("func"), "func",
-                                     ast::VariableList{}, ty.i32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("func", ast::VariableList{}, ty.i32,
+                    ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -1756,10 +1734,8 @@
 TEST_F(TypeDeterminerTest, StorageClass_DoesNotSetOnConst) {
   auto* var = Const("var", ast::StorageClass::kNone, ty.i32);
   auto* stmt = create<ast::VariableDeclStatement>(var);
-  auto* body = create<ast::BlockStatement>(ast::StatementList{stmt});
-  auto* func = create<ast::Function>(mod->RegisterSymbol("func"), "func",
-                                     ast::VariableList{}, ty.i32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("func", ast::VariableList{}, ty.i32,
+                    ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -1771,10 +1747,8 @@
   auto* var = Var("var", ast::StorageClass::kWorkgroup, ty.i32);
 
   auto* stmt = create<ast::VariableDeclStatement>(var);
-  auto* body = create<ast::BlockStatement>(ast::StatementList{stmt});
-  auto* func = create<ast::Function>(mod->RegisterSymbol("func"), "func",
-                                     ast::VariableList{}, ty.i32, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("func", ast::VariableList{}, ty.i32,
+                    ast::StatementList{stmt}, ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -2886,51 +2860,40 @@
   // ep_2 -> {}
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{});
-  auto* func_b =
-      create<ast::Function>(mod->RegisterSymbol("b"), "b", params, ty.f32, body,
-                            ast::FunctionDecorationList{});
-
-  body = create<ast::BlockStatement>(
-
-      ast::StatementList{
-          create<ast::AssignmentStatement>(Expr("second"), Call("b")),
-      });
+  auto* func_b = Func("b", params, ty.f32, ast::StatementList{},
+                      ast::FunctionDecorationList{});
   auto* func_c =
-      create<ast::Function>(mod->RegisterSymbol("c"), "c", params, ty.f32, body,
-                            ast::FunctionDecorationList{});
+      Func("c", params, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("second"), Call("b")),
+           },
+           ast::FunctionDecorationList{});
 
-  body = create<ast::BlockStatement>(
-
-      ast::StatementList{
-          create<ast::AssignmentStatement>(Expr("first"), Call("c")),
-      });
   auto* func_a =
-      create<ast::Function>(mod->RegisterSymbol("a"), "a", params, ty.f32, body,
-                            ast::FunctionDecorationList{});
+      Func("a", params, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("first"), Call("c")),
+           },
+           ast::FunctionDecorationList{});
 
-  body = create<ast::BlockStatement>(
+  auto* ep_1 =
+      Func("ep_1", params, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("call_a"), Call("a")),
+               create<ast::AssignmentStatement>(Expr("call_b"), Call("b")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
-      ast::StatementList{
-          create<ast::AssignmentStatement>(Expr("call_a"), Call("a")),
-          create<ast::AssignmentStatement>(Expr("call_b"), Call("b")),
-      });
-  auto* ep_1 = create<ast::Function>(
-      mod->RegisterSymbol("ep_1"), "ep_1", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
-
-  body = create<ast::BlockStatement>(
-
-      ast::StatementList{
-          create<ast::AssignmentStatement>(Expr("call_c"), Call("c")),
-      });
-  auto* ep_2 = create<ast::Function>(
-      mod->RegisterSymbol("ep_2"), "ep_2", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* ep_2 =
+      Func("ep_2", params, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("call_c"), Call("c")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func_b);
   mod->AddFunction(func_c);
diff --git a/src/validator/validator_function_test.cc b/src/validator/validator_function_test.cc
index 5d2b246..b4855fe 100644
--- a/src/validator/validator_function_test.cc
+++ b/src/validator/validator_function_test.cc
@@ -41,13 +41,11 @@
   auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
                   ast::VariableDecorationList{});
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-  });
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
-      params, ty.void_, body,
+  auto* func = Func(
+      Source{Source::Location{12, 34}}, "func", ast::VariableList{}, ty.void_,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(var),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
@@ -61,13 +59,12 @@
        VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
   // [[stage(vertex)]]
   // fn func -> void {}
-  ast::VariableList params;
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
-      params, ty.void_, create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
+           ty.void_, ast::StatementList{},
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -80,13 +77,12 @@
   auto* var = Var("a", ast::StorageClass::kNone, ty.i32, Expr(2),
                   ast::VariableDecorationList{});
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-  });
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
-      params, ty.i32, body, ast::FunctionDecorationList{});
+  auto* func = Func(Source{Source::Location{12, 34}}, "func",
+                    ast::VariableList{}, ty.i32,
+                    ast::StatementList{
+                        create<ast::VariableDeclStatement>(var),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -97,11 +93,9 @@
 
 TEST_F(ValidateFunctionTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
   // fn func -> int {}
-  ast::VariableList params;
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
-      params, ty.i32, create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func =
+      Func(Source{Source::Location{12, 34}}, "func", ast::VariableList{},
+           ty.i32, ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -113,16 +107,14 @@
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_Pass) {
   // [[stage(vertex)]]
   // fn func -> void { return; }
-  ast::VariableList params;
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("func"), "func", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->DetermineFunctions(mod->functions())) << td()->error();
@@ -131,17 +123,12 @@
 
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementType_fail) {
   // fn func -> void { return 2; }
-  ast::VariableList params;
-  auto* return_expr = Expr(2);
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
-                                   return_expr),
-  });
-
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(
+                            Source{Source::Location{12, 34}}, Expr(2)),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -154,17 +141,12 @@
 
 TEST_F(ValidateFunctionTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
   // fn func -> f32 { return 2; }
-  ast::VariableList params;
-  auto* return_expr = Expr(2);
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
-                                   return_expr),
-  });
-
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.f32,
-                            body, ast::FunctionDecorationList{});
+  auto* func = Func("func", ast::VariableList{}, ty.f32,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(
+                            Source{Source::Location{12, 34}}, Expr(2)),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -178,26 +160,18 @@
 TEST_F(ValidateFunctionTest, FunctionNamesMustBeUnique_fail) {
   // fn func -> i32 { return 2; }
   // fn func -> i32 { return 2; }
+  auto* func = Func("func", ast::VariableList{}, ty.i32,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(Expr(2)),
+                    },
+                    ast::FunctionDecorationList{});
 
-  ast::VariableList params;
-  auto* return_expr = Expr(2);
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(return_expr),
-  });
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params, ty.i32,
-                            body, ast::FunctionDecorationList{});
-
-  ast::VariableList params_copy;
-  auto* return_expr_copy = Expr(2);
-  auto* body_copy = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(return_expr_copy),
-  });
-
-  auto* func_copy = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("func"), "func",
-      params_copy, ty.i32, body_copy, ast::FunctionDecorationList{});
+  auto* func_copy = Func(Source{Source::Location{12, 34}}, "func",
+                         ast::VariableList{}, ty.i32,
+                         ast::StatementList{
+                             create<ast::ReturnStatement>(Expr(2)),
+                         },
+                         ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   mod->AddFunction(func_copy);
@@ -212,14 +186,13 @@
   ast::ExpressionList call_params;
   auto* call_expr = create<ast::CallExpression>(
       Source{Source::Location{12, 34}}, Expr("func"), call_params);
-  ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::CallStatement>(call_expr),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func0 =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
-                            ty.f32, body0, ast::FunctionDecorationList{});
+
+  auto* func0 = Func("func", ast::VariableList{}, ty.f32,
+                     ast::StatementList{
+                         create<ast::CallStatement>(call_expr),
+                         create<ast::ReturnStatement>(),
+                     },
+                     ast::FunctionDecorationList{});
   mod->AddFunction(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -235,17 +208,12 @@
   auto* var = Var("a", ast::StorageClass::kNone, ty.i32, call_expr,
                   ast::VariableDecorationList{});
 
-  ast::VariableList params0;
-  auto* return_expr = Expr(2);
-
-  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(return_expr),
-  });
-
-  auto* func0 =
-      create<ast::Function>(mod->RegisterSymbol("func"), "func", params0,
-                            ty.i32, body0, ast::FunctionDecorationList{});
+  auto* func0 = Func("func", ast::VariableList{}, ty.i32,
+                     ast::StatementList{
+                         create<ast::VariableDeclStatement>(var),
+                         create<ast::ReturnStatement>(Expr(2)),
+                     },
+                     ast::FunctionDecorationList{});
   mod->AddFunction(func0);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -256,15 +224,11 @@
 TEST_F(ValidateFunctionTest, Function_WithPipelineStage_NotVoid_Fail) {
   // [[stage(vertex)]]
   // fn vtx_main() -> i32 { return 0; }
-  ast::VariableList params;
-  auto* return_expr = Expr(0);
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(return_expr),
-  });
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_main"),
-      "vtx_main", params, ty.i32, body,
+  auto* func = Func(
+      Source{Source::Location{12, 34}}, "vtx_main", ast::VariableList{}, ty.i32,
+      ast::StatementList{
+          create<ast::ReturnStatement>(Expr(0)),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
       });
@@ -279,18 +243,17 @@
 TEST_F(ValidateFunctionTest, Function_WithPipelineStage_WithParams_Fail) {
   // [[stage(vertex)]]
   // fn vtx_func(a : i32) -> void { return; }
-  ast::VariableList params;
-  params.push_back(Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
-                       ast::VariableDecorationList{}));
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("vtx_func"),
-      "vtx_func", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func(Source{Source::Location{12, 34}}, "vtx_func",
+           ast::VariableList{Var("a", ast::StorageClass::kNone, ty.i32, nullptr,
+                                 ast::VariableDecorationList{})},
+           ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func);
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -304,13 +267,11 @@
   // [[stage(fragment)]]
   // [[stage(vertex)]]
   // fn main() -> void { return; }
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      Source{Source::Location{12, 34}}, mod->RegisterSymbol("main"), "main",
-      params, ty.void_, body,
+  auto* func = Func(
+      Source{Source::Location{12, 34}}, "main", ast::VariableList{}, ty.void_,
+      ast::StatementList{
+          create<ast::ReturnStatement>(),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex),
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
@@ -327,15 +288,14 @@
 TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Pass) {
   // [[stage(vertex)]]
   // fn vtx_func() -> void { return; }
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("vtx_func"), "vtx_func", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("vtx_func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -344,13 +304,11 @@
 
 TEST_F(ValidateFunctionTest, OnePipelineStageFunctionMustBePresent_Fail) {
   // fn vtx_func() -> void { return; }
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("vtx_func"), "vtx_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("vtx_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index 7a19bb5..bc37db6 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -255,15 +255,12 @@
   auto* lhs = Expr("not_global_var");
   auto* rhs = Expr(3.14f);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
-                                       rhs),
-  });
-
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.f32,
+                    ast::StatementList{
+                        create<ast::AssignmentStatement>(
+                            Source{Source::Location{12, 34}}, lhs, rhs),
+                    },
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   EXPECT_FALSE(v()->Validate(mod));
@@ -284,19 +281,16 @@
       mod->RegisterSymbol("global_var"), "global_var");
   auto* rhs = Expr(3.14f);
 
-  ast::VariableList params;
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Source{Source::Location{12, 34}}, lhs,
-                                       rhs),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("my_func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(
+                   Source{Source::Location{12, 34}}, lhs, rhs),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
@@ -435,14 +429,13 @@
 
   auto* var = Var("a", ast::StorageClass::kNone, ty.f32, Expr(2.0f),
                   ast::VariableDecorationList{});
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
-  });
 
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::VariableDeclStatement>(
+                            Source{Source::Location{12, 34}}, var),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -463,16 +456,13 @@
   auto* var_a_float = Var("a", ast::StorageClass::kNone, ty.f32, Expr(0.1f),
                           ast::VariableDecorationList{});
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
-                                         var_a_float),
-  });
-
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::VariableDeclStatement>(var),
+                        create<ast::VariableDeclStatement>(
+                            Source{Source::Location{12, 34}}, var_a_float),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -547,28 +537,24 @@
   auto* var1 = Var("a", ast::StorageClass::kNone, ty.void_, Expr(1.0f),
                    ast::VariableDecorationList{});
 
-  ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}},
-                                         var0),
-      create<ast::ReturnStatement>(),
-  });
+  auto* func0 = Func("func0", ast::VariableList{}, ty.void_,
+                     ast::StatementList{
+                         create<ast::VariableDeclStatement>(
+                             Source{Source::Location{12, 34}}, var0),
+                         create<ast::ReturnStatement>(),
+                     },
+                     ast::FunctionDecorationList{});
 
-  auto* func0 =
-      create<ast::Function>(mod->RegisterSymbol("func0"), "func0", params0,
-                            ty.void_, body0, ast::FunctionDecorationList{});
-
-  ast::VariableList params1;
-  auto* body1 = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(Source{Source::Location{13, 34}},
-                                         var1),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func1 = create<ast::Function>(
-      mod->RegisterSymbol("func1"), "func1", params1, ty.void_, body1,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func1 =
+      Func("func1", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(
+                   Source{Source::Location{13, 34}}, var1),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func0);
   mod->AddFunction(func1);
diff --git a/src/validator/validator_type_test.cc b/src/validator/validator_type_test.cc
index 1bc997c..597ce7d 100644
--- a/src/validator/validator_type_test.cc
+++ b/src/validator/validator_type_test.cc
@@ -149,15 +149,15 @@
   // fn func -> void { var a : array<i32>; }
 
   auto* var = Var("a", ast::StorageClass::kNone, ty.array<i32>());
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(Source{Source::Location{12, 34}}, var),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("func"), "func", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(
+                   Source{Source::Location{12, 34}}, var),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
   mod->AddFunction(func);
 
   EXPECT_TRUE(td()->Determine()) << td()->error();
diff --git a/src/writer/hlsl/generator_impl_binary_test.cc b/src/writer/hlsl/generator_impl_binary_test.cc
index cce256a..457acde 100644
--- a/src/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/writer/hlsl/generator_impl_binary_test.cc
@@ -459,10 +459,8 @@
 TEST_F(HlslGeneratorImplTest_Binary, Call_WithLogical) {
   // foo(a && b, c || d, (a || c) && (b || d))
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("foo"), "foo", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("foo", ast::VariableList{}, ty.void_, ast::StatementList{},
+                    ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ast::ExpressionList params;
diff --git a/src/writer/hlsl/generator_impl_call_test.cc b/src/writer/hlsl/generator_impl_call_test.cc
index 5cb1e0a..c9b40b4 100644
--- a/src/writer/hlsl/generator_impl_call_test.cc
+++ b/src/writer/hlsl/generator_impl_call_test.cc
@@ -32,10 +32,8 @@
 TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
   auto* call = Call("my_func");
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
@@ -45,10 +43,8 @@
 TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
   auto* call = Call("my_func", "param1", "param2");
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, call)) << gen.error();
@@ -58,10 +54,8 @@
 TEST_F(HlslGeneratorImplTest_Call, EmitStatement_Call) {
   auto* call = create<ast::CallStatement>(Call("my_func", "param1", "param2"));
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
   gen.increment_indent();
   ASSERT_TRUE(gen.EmitStatement(out, call)) << 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 366ab7a..6bce585 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
@@ -60,16 +60,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("vtx_main"), "vtx_main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("vtx_main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func);
 
@@ -111,17 +110,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("vtx_main"), "vtx_main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("vtx_main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func);
 
@@ -163,17 +160,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kVertex),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kVertex),
+           });
 
   mod->AddFunction(func);
 
@@ -215,16 +210,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -263,16 +257,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+           });
 
   mod->AddFunction(func);
 
@@ -306,16 +299,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.f32, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.f32,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("foo"), Expr("foo")),
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("bar")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+           });
 
   mod->AddFunction(func);
 
@@ -357,16 +349,15 @@
   mod->AddGlobalVariable(coord_var);
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("depth"),
-                                       MemberAccessor("coord", "x")),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("depth"),
+                                                MemberAccessor("coord", "x")),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index 7ac56d4..7f3741e 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -53,12 +53,11 @@
 using HlslGeneratorImplTest_Function = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                     ast::VariableList{}, ty.void_, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -72,12 +71,11 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("GeometryShader"), "GeometryShader",
-      ast::VariableList{}, ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("GeometryShader", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -91,16 +89,15 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
-  ast::VariableList params;
-  params.push_back(Var("a", ast::StorageClass::kNone, ty.f32));
-  params.push_back(Var("b", ast::StorageClass::kNone, ty.i32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
   auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+      Func("my_func",
+           ast::VariableList{Var("a", ast::StorageClass::kNone, ty.f32),
+                             Var("b", ast::StorageClass::kNone, ty.i32)},
+           ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -131,16 +128,15 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -183,17 +179,16 @@
   mod->AddGlobalVariable(coord_var);
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("depth"),
-                                       MemberAccessor("coord", "x")),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("depth"),
+                                                MemberAccessor("coord", "x")),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -228,19 +223,18 @@
   td.RegisterVariableForTesting(coord_var);
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   MemberAccessor("coord", "x"), ast::VariableDecorationList{});
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -277,21 +271,20 @@
   td.RegisterVariableForTesting(coord_var);
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   create<ast::MemberAccessorExpression>(
                       MemberAccessor("uniforms", "coord"), Expr("x")),
                   ast::VariableDecorationList{});
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -331,19 +324,18 @@
   td.RegisterVariableForTesting(coord_var);
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   MemberAccessor("coord", "b"), ast::VariableDecorationList{});
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -380,19 +372,18 @@
   td.RegisterVariableForTesting(coord_var);
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   MemberAccessor("coord", "b"), ast::VariableDecorationList{});
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -426,21 +417,18 @@
           });
 
   td.RegisterVariableForTesting(coord_var);
-
   mod->AddGlobalVariable(coord_var);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(MemberAccessor("coord", "b"),
-                                       Expr(2.0f)),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", ast::VariableList{},
-      ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(MemberAccessor("coord", "b"),
+                                                Expr(2.0f)),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -483,26 +471,25 @@
   mod->AddGlobalVariable(bar_var);
   mod->AddGlobalVariable(val_var);
 
-  ast::VariableList params;
-  params.push_back(Var("param", ast::StorageClass::kFunction, ty.f32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
-      create<ast::AssignmentStatement>(Expr("val"), Expr("param")),
-      create<ast::ReturnStatement>(Expr("foo")),
-  });
-  auto* sub_func =
-      create<ast::Function>(mod->RegisterSymbol("sub_func"), "sub_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* sub_func = Func(
+      "sub_func",
+      ast::VariableList{Var("param", ast::StorageClass::kFunction, ty.f32)},
+      ty.f32,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("bar"), Expr("foo")),
+          create<ast::AssignmentStatement>(Expr("val"), Expr("param")),
+          create<ast::ReturnStatement>(Expr("foo")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("bar"), Call("sub_func", 1.0f)),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func_1 = create<ast::Function>(
-      mod->RegisterSymbol("ep_1"), "ep_1", params, ty.void_, body,
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, ty.void_,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("bar"), Call("sub_func", 1.0f)),
+          create<ast::ReturnStatement>(),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
@@ -547,27 +534,27 @@
 
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-  params.push_back(Var("param", ast::StorageClass::kFunction, ty.f32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(Expr("param")),
-  });
-  auto* sub_func =
-      create<ast::Function>(mod->RegisterSymbol("sub_func"), "sub_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* sub_func = Func(
+      "sub_func",
+      ast::VariableList{Var("param", ast::StorageClass::kFunction, ty.f32)},
+      ty.f32,
+      ast::StatementList{
+          create<ast::ReturnStatement>(Expr("param")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func_1 = create<ast::Function>(
-      mod->RegisterSymbol("ep_1"), "ep_1", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func_1 =
+      Func("ep_1", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("depth"),
+                                                Call("sub_func", 1.0f)),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func_1);
 
@@ -612,29 +599,29 @@
   mod->AddGlobalVariable(coord_var);
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-  params.push_back(Var("param", ast::StorageClass::kFunction, ty.f32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("depth"),
-                                       MemberAccessor("coord", "x")),
-      create<ast::ReturnStatement>(Expr("param")),
-  });
-  auto* sub_func =
-      create<ast::Function>(mod->RegisterSymbol("sub_func"), "sub_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* sub_func = Func(
+      "sub_func",
+      ast::VariableList{Var("param", ast::StorageClass::kFunction, ty.f32)},
+      ty.f32,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("depth"),
+                                           MemberAccessor("coord", "x")),
+          create<ast::ReturnStatement>(Expr("param")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("depth"), Call("sub_func", 1.0f)),
-      create<ast::ReturnStatement>(),
-  });
-  auto* func_1 = create<ast::Function>(
-      mod->RegisterSymbol("ep_1"), "ep_1", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func_1 =
+      Func("ep_1", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("depth"),
+                                                Call("sub_func", 1.0f)),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func_1);
 
@@ -675,32 +662,29 @@
 
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
-  params.push_back(Var("param", ast::StorageClass::kFunction, ty.f32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
-  });
-
-  auto* sub_func =
-      create<ast::Function>(mod->RegisterSymbol("sub_func"), "sub_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* sub_func = Func(
+      "sub_func",
+      ast::VariableList{Var("param", ast::StorageClass::kFunction, ty.f32)},
+      ty.f32,
+      ast::StatementList{
+          create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   Call("sub_func", 1.0f), ast::VariableDecorationList{});
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -736,32 +720,29 @@
 
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
-  params.push_back(Var("param", ast::StorageClass::kFunction, ty.f32));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
-  });
-
-  auto* sub_func =
-      create<ast::Function>(mod->RegisterSymbol("sub_func"), "sub_func", params,
-                            ty.f32, body, ast::FunctionDecorationList{});
+  auto* sub_func = Func(
+      "sub_func",
+      ast::VariableList{Var("param", ast::StorageClass::kFunction, ty.f32)},
+      ty.f32,
+      ast::StatementList{
+          create<ast::ReturnStatement>(MemberAccessor("coord", "x")),
+      },
+      ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
   auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                   Call("sub_func", 1.0f), ast::VariableDecorationList{});
 
-  body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::VariableDeclStatement>(var),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("frag_main"), "frag_main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("frag_main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::VariableDeclStatement>(var),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   mod->AddFunction(func);
 
@@ -795,17 +776,15 @@
       create<ast::ReturnStatement>(),
   });
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("bar"), Expr(1.0f)),
-      create<ast::IfStatement>(create<ast::BinaryExpression>(
-                                   ast::BinaryOp::kEqual, Expr(1), Expr(1)),
-                               list, ast::ElseStatementList{}),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func_1 = create<ast::Function>(
-      mod->RegisterSymbol("ep_1"), "ep_1", params, ty.void_, body,
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, ty.void_,
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Expr("bar"), Expr(1.0f)),
+          create<ast::IfStatement>(create<ast::BinaryExpression>(
+                                       ast::BinaryOp::kEqual, Expr(1), Expr(1)),
+                                   list, ast::ElseStatementList{}),
+          create<ast::ReturnStatement>(),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
@@ -832,10 +811,8 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_FunctionDecoration_EntryPoint_WithNameCollision) {
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("GeometryShader"), "GeometryShader",
-      ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
+  auto* func = Func(
+      "GeometryShader", ast::VariableList{}, ty.void_, ast::StatementList{},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment),
       });
@@ -851,16 +828,14 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_FunctionDecoration_EntryPoint_Compute) {
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+           });
 
   mod->AddFunction(func);
 
@@ -876,17 +851,15 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_FunctionDecoration_EntryPoint_Compute_WithWorkgroup) {
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("main"), "main", params, ty.void_, body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-          create<ast::WorkgroupDecoration>(2u, 4u, 6u),
-      });
+  auto* func =
+      Func("main", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+               create<ast::WorkgroupDecoration>(2u, 4u, 6u),
+           });
 
   mod->AddFunction(func);
 
@@ -903,15 +876,13 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
   ast::type::Array ary(ty.f32, 5, ast::ArrayDecorationList{});
 
-  ast::VariableList params;
-  params.push_back(Var("a", ast::StorageClass::kNone, &ary));
-
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::ReturnStatement>(),
-  });
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+  auto* func = Func("my_func",
+                    ast::VariableList{Var("a", ast::StorageClass::kNone, &ary)},
+                    ty.void_,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -960,39 +931,35 @@
   mod->AddGlobalVariable(data_var);
 
   {
-    ast::VariableList params;
     auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                     MemberAccessor("data", "d"), ast::VariableDecorationList{});
 
-    auto* body = create<ast::BlockStatement>(ast::StatementList{
-        create<ast::VariableDeclStatement>(var),
-        create<ast::ReturnStatement>(),
-    });
-
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol("a"), "a", params, ty.void_, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-        });
+    auto* func =
+        Func("a", ast::VariableList{}, ty.void_,
+             ast::StatementList{
+                 create<ast::VariableDeclStatement>(var),
+                 create<ast::ReturnStatement>(),
+             },
+             ast::FunctionDecorationList{
+                 create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+             });
 
     mod->AddFunction(func);
   }
 
   {
-    ast::VariableList params;
     auto* var = Var("v", ast::StorageClass::kFunction, ty.f32,
                     MemberAccessor("data", "d"), ast::VariableDecorationList{});
 
-    auto* body = create<ast::BlockStatement>(ast::StatementList{
-        create<ast::VariableDeclStatement>(var),
-        create<ast::ReturnStatement>(),
-    });
-
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol("b"), "b", params, ty.void_, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-        });
+    auto* func =
+        Func("b", ast::VariableList{}, ty.void_,
+             ast::StatementList{
+                 create<ast::VariableDeclStatement>(var),
+                 create<ast::ReturnStatement>(),
+             },
+             ast::FunctionDecorationList{
+                 create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+             });
 
     mod->AddFunction(func);
   }
diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc
index 0d1baa6..a3f2af4 100644
--- a/src/writer/hlsl/generator_impl_test.cc
+++ b/src/writer/hlsl/generator_impl_test.cc
@@ -29,10 +29,8 @@
 
 TEST_F(HlslGeneratorImplTest, Generate) {
   ast::type::Void void_type;
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, &void_type,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
diff --git a/src/writer/msl/generator_impl_call_test.cc b/src/writer/msl/generator_impl_call_test.cc
index da88386..ea149a3 100644
--- a/src/writer/msl/generator_impl_call_test.cc
+++ b/src/writer/msl/generator_impl_call_test.cc
@@ -38,10 +38,8 @@
       Source{}, mod->RegisterSymbol("my_func"), "my_func");
   ast::CallExpression call(Source{}, id, {});
 
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, &void_type,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(&call)) << gen.error();
@@ -60,10 +58,8 @@
       Source{}, mod->RegisterSymbol("param2"), "param2"));
   ast::CallExpression call(Source{}, id, params);
 
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, &void_type,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(&call)) << gen.error();
@@ -83,10 +79,8 @@
   ast::CallStatement call(Source{},
                           create<ast::CallExpression>(Source{}, id, params));
 
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, &void_type,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   gen.increment_indent();
diff --git a/src/writer/msl/generator_impl_function_entry_point_data_test.cc b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
index fe17c53..0851047 100644
--- a/src/writer/msl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
@@ -80,24 +80,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("vtx_main"), "vtx_main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "vtx_main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
       });
@@ -157,24 +155,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("vtx_main"), "vtx_main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "vtx_main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kVertex),
       });
@@ -234,24 +230,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -311,24 +305,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -385,24 +377,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kCompute),
       });
@@ -454,24 +444,22 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar")),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", params, &f32, body,
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar")),
+  };
+  auto* func = Func(
+      "main", ast::VariableList{}, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kCompute),
       });
@@ -529,24 +517,20 @@
   mod->AddGlobalVariable(coord_var);
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("depth"), "depth"),
+          create<ast::MemberAccessorExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("depth"), "depth"),
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("x"), "x"))),
-      });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", params, &void_type, body,
+                  Source{}, mod->RegisterSymbol("coord"), "coord"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("x"), "x"))),
+  };
+  auto* func = Func(
+      "main", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index b7e539e..f926bbf 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -58,14 +58,11 @@
 TEST_F(MslGeneratorImplTest, Emit_Function) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"),
-                                     "my_func", ast::VariableList{}, &void_type,
-                                     body, ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, &void_type,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(Source{}),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -83,14 +80,11 @@
 TEST_F(MslGeneratorImplTest, Emit_Function_Name_Collision) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("main"),
-                                     "main", ast::VariableList{}, &void_type,
-                                     body, ast::FunctionDecorationList{});
+  auto* func = Func("main", ast::VariableList{}, &void_type,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(Source{}),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -129,14 +123,11 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"),
-                                     "my_func", params, &void_type, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("my_func", params, &void_type,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(Source{}),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
   gen.increment_indent();
@@ -185,22 +176,18 @@
   mod->AddGlobalVariable(foo_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::AssignmentStatement>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("bar"), "bar"),
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
-      ast::FunctionDecorationList{create<ast::StageDecoration>(
-          Source{}, ast::PipelineStage::kFragment)});
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::ReturnStatement>(Source{}),
+  };
+  auto* func = Func("frag_main", ast::VariableList{}, &void_type, body,
+                    ast::FunctionDecorationList{create<ast::StageDecoration>(
+                        Source{}, ast::PipelineStage::kFragment)});
 
   mod->AddFunction(func);
 
@@ -262,25 +249,21 @@
   mod->AddGlobalVariable(coord_var);
   mod->AddGlobalVariable(depth_var);
 
-  ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("depth"), "depth"),
+          create<ast::MemberAccessorExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("depth"), "depth"),
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("x"), "x"))),
-          create<ast::ReturnStatement>(Source{}),
-      });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+                  Source{}, mod->RegisterSymbol("coord"), "coord"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("x"), "x"))),
+      create<ast::ReturnStatement>(Source{}),
+  };
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -327,7 +310,6 @@
 
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = create<ast::Variable>(
       Source{},                      // source
       "v",                           // name
@@ -342,14 +324,12 @@
                                             "x")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -400,7 +380,6 @@
 
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
   auto* var = create<ast::Variable>(
       Source{},                      // source
       "v",                           // name
@@ -415,14 +394,12 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -474,11 +451,8 @@
                             });
 
   td.RegisterVariableForTesting(coord_var);
-
   mod->AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
-
   auto* var = create<ast::Variable>(
       Source{},                      // source
       "v",                           // name
@@ -493,14 +467,12 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -585,28 +557,25 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
-              Source{},
-              create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("bar"), "bar"),
-              create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("foo"), "foo")),
-          create<ast::AssignmentStatement>(
-              Source{},
-              create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("val"), "val"),
-              create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("param"), "param")),
-          create<ast::ReturnStatement>(
-              Source{}, create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("foo"), "foo")),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, &f32, body,
-      ast::FunctionDecorationList{});
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("foo"), "foo")),
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("val"), "val"),
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("param"), "param")),
+      create<ast::ReturnStatement>(
+          Source{}, create<ast::IdentifierExpression>(
+                        Source{}, mod->RegisterSymbol("foo"), "foo")),
+  };
+  auto* sub_func =
+      Func("sub_func", params, &f32, body, ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
@@ -614,22 +583,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::CallExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("bar"), "bar"),
-              create<ast::CallExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
-                  expr)),
-          create<ast::ReturnStatement>(Source{}),
-      });
-  auto* func_1 = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_1"), "ep_1", params, &void_type, body,
+                  Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
+              expr)),
+      create<ast::ReturnStatement>(Source{}),
+  };
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -697,15 +664,13 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
+  auto* sub_func = Func(
+      "sub_func", params, &f32,
       ast::StatementList{
           create<ast::ReturnStatement>(
               Source{}, create<ast::IdentifierExpression>(
                             Source{}, mod->RegisterSymbol("param"), "param")),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, &f32, body,
+      },
       ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
@@ -714,23 +679,21 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("depth"), "depth"),
+          create<ast::CallExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("depth"), "depth"),
-              create<ast::CallExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
-                  expr)),
-          create<ast::ReturnStatement>(Source{}),
-      });
+                  Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
+              expr)),
+      create<ast::ReturnStatement>(Source{}),
+  };
 
-  auto* func_1 = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_1"), "ep_1", params, &void_type, body,
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -806,26 +769,23 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("depth"), "depth"),
+          create<ast::MemberAccessorExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("depth"), "depth"),
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("x"), "x"))),
-          create<ast::ReturnStatement>(
-              Source{}, create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("param"), "param")),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, &f32, body,
-      ast::FunctionDecorationList{});
+                  Source{}, mod->RegisterSymbol("coord"), "coord"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("x"), "x"))),
+      create<ast::ReturnStatement>(
+          Source{}, create<ast::IdentifierExpression>(
+                        Source{}, mod->RegisterSymbol("param"), "param")),
+  };
+  auto* sub_func =
+      Func("sub_func", params, &f32, body, ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
@@ -833,22 +793,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
+  body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(
+              Source{}, mod->RegisterSymbol("depth"), "depth"),
+          create<ast::CallExpression>(
               Source{},
               create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("depth"), "depth"),
-              create<ast::CallExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
-                  expr)),
-          create<ast::ReturnStatement>(Source{}),
-      });
-  auto* func_1 = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_1"), "ep_1", params, &void_type, body,
+                  Source{}, mod->RegisterSymbol("sub_func"), "sub_func"),
+              expr)),
+      create<ast::ReturnStatement>(Source{}),
+  };
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -910,21 +868,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::ReturnStatement>(
-              Source{},
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("x"), "x"))),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, &f32, body,
-      ast::FunctionDecorationList{});
+  auto body = ast::StatementList{
+      create<ast::ReturnStatement>(
+          Source{}, create<ast::MemberAccessorExpression>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("coord"), "coord"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("x"), "x"))),
+  };
+  auto* sub_func =
+      Func("sub_func", params, &f32, body, ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
@@ -945,15 +899,12 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -1016,21 +967,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::ReturnStatement>(
-              Source{},
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("b"), "b"))),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, ty.f32,
-      body, ast::FunctionDecorationList{});
+  auto body = ast::StatementList{
+      create<ast::ReturnStatement>(
+          Source{}, create<ast::MemberAccessorExpression>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("coord"), "coord"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("b"), "b"))),
+  };
+  auto* sub_func =
+      Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
@@ -1051,15 +998,12 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -1128,21 +1072,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::ReturnStatement>(
-              Source{},
-              create<ast::MemberAccessorExpression>(
-                  Source{},
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("coord"), "coord"),
-                  create<ast::IdentifierExpression>(
-                      Source{}, mod->RegisterSymbol("b"), "b"))),
-      });
-  auto* sub_func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("sub_func"), "sub_func", params, ty.f32,
-      body, ast::FunctionDecorationList{});
+  auto body = ast::StatementList{
+      create<ast::ReturnStatement>(
+          Source{}, create<ast::MemberAccessorExpression>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("coord"), "coord"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("b"), "b"))),
+  };
+  auto* sub_func =
+      Func("sub_func", params, ty.f32, body, ast::FunctionDecorationList{});
 
   mod->AddFunction(sub_func);
 
@@ -1163,15 +1103,12 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::VariableDeclStatement>(Source{}, var),
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+  auto* func = Func(
+      "frag_main", ast::VariableList{}, &void_type,
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::ReturnStatement>(Source{}),
+      },
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -1221,35 +1158,32 @@
   td.RegisterVariableForTesting(bar_var);
   mod->AddGlobalVariable(bar_var);
 
-  ast::VariableList params;
   auto* list = create<ast::BlockStatement>(
       Source{}, ast::StatementList{
                     create<ast::ReturnStatement>(Source{}),
                 });
 
-  auto* body = create<ast::BlockStatement>(
-      Source{},
-      ast::StatementList{
-          create<ast::AssignmentStatement>(
-              Source{},
-              create<ast::IdentifierExpression>(
-                  Source{}, mod->RegisterSymbol("bar"), "bar"),
+  auto body = ast::StatementList{
+      create<ast::AssignmentStatement>(
+          Source{},
+          create<ast::IdentifierExpression>(Source{},
+                                            mod->RegisterSymbol("bar"), "bar"),
+          create<ast::ScalarConstructorExpression>(
+              Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))),
+      create<ast::IfStatement>(
+          Source{},
+          create<ast::BinaryExpression>(
+              Source{}, ast::BinaryOp::kEqual,
               create<ast::ScalarConstructorExpression>(
-                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))),
-          create<ast::IfStatement>(
-              Source{},
-              create<ast::BinaryExpression>(
-                  Source{}, ast::BinaryOp::kEqual,
-                  create<ast::ScalarConstructorExpression>(
-                      Source{}, create<ast::SintLiteral>(Source{}, &i32, 1)),
-                  create<ast::ScalarConstructorExpression>(
-                      Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
-              list, ast::ElseStatementList{}),
-          create<ast::ReturnStatement>(Source{}),
-      });
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1)),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+          list, ast::ElseStatementList{}),
+      create<ast::ReturnStatement>(Source{}),
+  };
 
-  auto* func_1 = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("ep_1"), "ep_1", params, &void_type, body,
+  auto* func_1 = Func(
+      "ep_1", ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kFragment),
       });
@@ -1280,9 +1214,8 @@
        Emit_FunctionDecoration_EntryPoint_WithNameCollision) {
   ast::type::Void void_type;
 
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+  auto* func = Func(
+      "main", ast::VariableList{}, &void_type, ast::StatementList{},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kCompute),
       });
@@ -1314,14 +1247,11 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(
-      Source{}, ast::StatementList{
-                    create<ast::ReturnStatement>(Source{}),
-                });
-
-  auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"),
-                                     "my_func", params, &void_type, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("my_func", params, &void_type,
+                    ast::StatementList{
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
 
   mod->AddFunction(func);
 
@@ -1385,7 +1315,6 @@
   mod->AddGlobalVariable(data_var);
 
   {
-    ast::VariableList params;
     auto* var = create<ast::Variable>(
         Source{},                      // source
         "v",                           // name
@@ -1401,23 +1330,20 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::VariableDeclStatement>(Source{}, var),
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    auto* func = create<ast::Function>(
-        Source{}, mod->RegisterSymbol("a"), "a", params, &void_type, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(Source{},
-                                         ast::PipelineStage::kCompute),
-        });
+    auto* func = Func("a", ast::VariableList{}, &void_type,
+                      ast::StatementList{
+                          create<ast::VariableDeclStatement>(Source{}, var),
+                          create<ast::ReturnStatement>(Source{}),
+                      },
+                      ast::FunctionDecorationList{
+                          create<ast::StageDecoration>(
+                              Source{}, ast::PipelineStage::kCompute),
+                      });
 
     mod->AddFunction(func);
   }
 
   {
-    ast::VariableList params;
     auto* var = create<ast::Variable>(
         Source{},                      // source
         "v",                           // name
@@ -1433,17 +1359,15 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::VariableDeclStatement>(Source{}, var),
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    auto* func = create<ast::Function>(
-        Source{}, mod->RegisterSymbol("b"), "b", params, &void_type, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(Source{},
-                                         ast::PipelineStage::kCompute),
-        });
+    auto* func = Func("b", ast::VariableList{}, &void_type,
+                      ast::StatementList{
+                          create<ast::VariableDeclStatement>(Source{}, var),
+                          create<ast::ReturnStatement>(Source{}),
+                      },
+                      ast::FunctionDecorationList{
+                          create<ast::StageDecoration>(
+                              Source{}, ast::PipelineStage::kCompute),
+                      });
 
     mod->AddFunction(func);
   }
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index cf6df0e..585f558 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -50,9 +50,8 @@
 TEST_F(MslGeneratorImplTest, Generate) {
   ast::type::Void void_type;
 
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+  auto* func = Func(
+      "my_func", ast::VariableList{}, &void_type, ast::StatementList{},
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(Source{}, ast::PipelineStage::kCompute),
       });
diff --git a/src/writer/spirv/builder_function_decoration_test.cc b/src/writer/spirv/builder_function_decoration_test.cc
index 4f28dc5..33fd143 100644
--- a/src/writer/spirv/builder_function_decoration_test.cc
+++ b/src/writer/spirv/builder_function_decoration_test.cc
@@ -352,13 +352,12 @@
           });
   mod->AddGlobalVariable(fragdepth);
 
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::AssignmentStatement>(Expr("fragdepth"), Expr(1.f)),
-  });
-
-  auto* func = create<ast::Function>(
-      Source{}, mod->RegisterSymbol("main"), "main", ast::VariableList{},
-      create<ast::type::Void>(), body, ast::FunctionDecorationList{});
+  auto* func =
+      Func("main", ast::VariableList{}, create<ast::type::Void>(),
+           ast::StatementList{
+               create<ast::AssignmentStatement>(Expr("fragdepth"), Expr(1.f)),
+           },
+           ast::FunctionDecorationList{});
 
   func->add_referenced_module_variable(fragdepth);
 
diff --git a/src/writer/spirv/builder_function_test.cc b/src/writer/spirv/builder_function_test.cc
index adc847a..600401c 100644
--- a/src/writer/spirv/builder_function_test.cc
+++ b/src/writer/spirv/builder_function_test.cc
@@ -299,7 +299,6 @@
   mod->AddGlobalVariable(data_var);
 
   {
-    ast::VariableList params;
     auto* var = create<ast::Variable>(
         Source{},                      // source
         "v",                           // name
@@ -315,23 +314,20 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::VariableDeclStatement>(Source{}, var),
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    auto* func = create<ast::Function>(
-        Source{}, mod->RegisterSymbol("a"), "a", params, &void_type, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(Source{},
-                                         ast::PipelineStage::kCompute),
-        });
+    auto* func = Func("a", ast::VariableList{}, &void_type,
+                      ast::StatementList{
+                          create<ast::VariableDeclStatement>(Source{}, var),
+                          create<ast::ReturnStatement>(Source{}),
+                      },
+                      ast::FunctionDecorationList{
+                          create<ast::StageDecoration>(
+                              Source{}, ast::PipelineStage::kCompute),
+                      });
 
     mod->AddFunction(func);
   }
 
   {
-    ast::VariableList params;
     auto* var = create<ast::Variable>(
         Source{},                      // source
         "v",                           // name
@@ -347,17 +343,15 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(
-        Source{}, ast::StatementList{
-                      create<ast::VariableDeclStatement>(Source{}, var),
-                      create<ast::ReturnStatement>(Source{}),
-                  });
-    auto* func = create<ast::Function>(
-        Source{}, mod->RegisterSymbol("b"), "b", params, &void_type, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(Source{},
-                                         ast::PipelineStage::kCompute),
-        });
+    auto* func = Func("b", ast::VariableList{}, &void_type,
+                      ast::StatementList{
+                          create<ast::VariableDeclStatement>(Source{}, var),
+                          create<ast::ReturnStatement>(Source{}),
+                      },
+                      ast::FunctionDecorationList{
+                          create<ast::StageDecoration>(
+                              Source{}, ast::PipelineStage::kCompute),
+                      });
 
     mod->AddFunction(func);
   }
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index 97b8028..e8e2fa7 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -471,10 +471,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
@@ -506,10 +504,8 @@
   auto* expr = Call(param.name, 1.0f);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -535,10 +531,8 @@
   auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -590,10 +584,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -616,10 +608,8 @@
   auto* expr = Call("length", vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -644,10 +634,8 @@
   auto* expr = Call("normalize", vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -677,10 +665,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -707,10 +693,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -745,10 +729,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -772,10 +754,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -802,10 +782,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -834,10 +812,8 @@
   auto* expr = Call(param.name, 1.0f, 1.0f, 1.0f);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -865,10 +841,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -907,10 +881,8 @@
   auto* expr = Call(param.name, 1);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -936,10 +908,8 @@
   auto* expr = Call(param.name, vec2<i32>(1, 1));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -972,10 +942,8 @@
   auto* expr = Call(param.name, 1u);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1001,10 +969,8 @@
   auto* expr = Call(param.name, vec2<u32>(1u, 1u));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1037,10 +1003,8 @@
   auto* expr = Call(param.name, 1, 1);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1066,10 +1030,8 @@
   auto* expr = Call(param.name, vec2<i32>(1, 1), vec2<i32>(1, 1));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1103,10 +1065,8 @@
   auto* expr = Call(param.name, 1u, 1u);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1132,10 +1092,8 @@
   auto* expr = Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(1u, 1u));
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1169,10 +1127,8 @@
   auto* expr = Call(param.name, 1, 1, 1);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1200,10 +1156,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1236,10 +1190,8 @@
   auto* expr = Call(param.name, 1u, 1u, 1u);
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1267,10 +1219,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1301,10 +1251,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
@@ -1344,10 +1292,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
@@ -1383,10 +1329,8 @@
 
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
@@ -1428,10 +1372,8 @@
   auto* expr = Call("arrayLength", "ptr_var");
   ASSERT_TRUE(td.DetermineResultType(expr)) << td.error();
 
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "a_func", ast::VariableList{}, ty.void_,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{});
+  auto* func = Func("a_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{}, ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
diff --git a/src/writer/wgsl/generator_impl_function_test.cc b/src/writer/wgsl/generator_impl_function_test.cc
index 2b224c3..59b7005 100644
--- a/src/writer/wgsl/generator_impl_function_test.cc
+++ b/src/writer/wgsl/generator_impl_function_test.cc
@@ -41,14 +41,12 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Function) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                                     ast::VariableList{}, ty.void_, body,
-                                     ast::FunctionDecorationList{});
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::DiscardStatement>(),
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{});
 
   gen.increment_indent();
 
@@ -61,18 +59,16 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithParams) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-      create<ast::ReturnStatement>(),
-  });
-
-  ast::VariableList params;
-  params.push_back(Var("a", ast::StorageClass::kNone, ty.f32));
-  params.push_back(Var("b", ast::StorageClass::kNone, ty.i32));
-
   auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func", params,
-                            ty.void_, body, ast::FunctionDecorationList{});
+      Func("my_func",
+           ast::VariableList{Var("a", ast::StorageClass::kNone, ty.f32),
+                             Var("b", ast::StorageClass::kNone, ty.i32)},
+           ty.void_,
+           ast::StatementList{
+               create<ast::DiscardStatement>(),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{});
 
   gen.increment_indent();
 
@@ -85,17 +81,14 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_WorkgroupSize) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func =
-      create<ast::Function>(mod->RegisterSymbol("my_func"), "my_func",
-                            ast::VariableList{}, ty.void_, body,
-                            ast::FunctionDecorationList{
-                                create<ast::WorkgroupDecoration>(2u, 4u, 6u),
-                            });
+  auto* func = Func("my_func", ast::VariableList{}, ty.void_,
+                    ast::StatementList{
+                        create<ast::DiscardStatement>(),
+                        create<ast::ReturnStatement>(),
+                    },
+                    ast::FunctionDecorationList{
+                        create<ast::WorkgroupDecoration>(2u, 4u, 6u),
+                    });
 
   gen.increment_indent();
 
@@ -109,17 +102,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_Stage) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.void_,
-      body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-      });
+  auto* func =
+      Func("my_func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::DiscardStatement>(),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+           });
 
   gen.increment_indent();
 
@@ -133,18 +124,16 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_Multiple) {
-  auto* body = create<ast::BlockStatement>(ast::StatementList{
-      create<ast::DiscardStatement>(),
-      create<ast::ReturnStatement>(),
-  });
-
-  auto* func = create<ast::Function>(
-      mod->RegisterSymbol("my_func"), "my_func", ast::VariableList{}, ty.void_,
-      body,
-      ast::FunctionDecorationList{
-          create<ast::StageDecoration>(ast::PipelineStage::kFragment),
-          create<ast::WorkgroupDecoration>(2u, 4u, 6u),
-      });
+  auto* func =
+      Func("my_func", ast::VariableList{}, ty.void_,
+           ast::StatementList{
+               create<ast::DiscardStatement>(),
+               create<ast::ReturnStatement>(),
+           },
+           ast::FunctionDecorationList{
+               create<ast::StageDecoration>(ast::PipelineStage::kFragment),
+               create<ast::WorkgroupDecoration>(2u, 4u, 6u),
+           });
 
   gen.increment_indent();
 
@@ -198,41 +187,39 @@
   mod->AddGlobalVariable(data_var);
 
   {
-    ast::VariableList params;
     auto* var =
         Var("v", ast::StorageClass::kFunction, ty.f32,
             create<ast::MemberAccessorExpression>(Expr("data"), Expr("d")),
             ast::VariableDecorationList{});
 
-    auto* body = create<ast::BlockStatement>(ast::StatementList{
-        create<ast::VariableDeclStatement>(var),
-        create<ast::ReturnStatement>(),
-    });
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol("a"), "a", params, ty.void_, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-        });
+    auto* func =
+        Func("a", ast::VariableList{}, ty.void_,
+             ast::StatementList{
+                 create<ast::VariableDeclStatement>(var),
+                 create<ast::ReturnStatement>(),
+             },
+             ast::FunctionDecorationList{
+                 create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+             });
 
     mod->AddFunction(func);
   }
 
   {
-    ast::VariableList params;
     auto* var =
         Var("v", ast::StorageClass::kFunction, ty.f32,
             create<ast::MemberAccessorExpression>(Expr("data"), Expr("d")),
             ast::VariableDecorationList{});
 
-    auto* body = create<ast::BlockStatement>(ast::StatementList{
-        create<ast::VariableDeclStatement>(var),
-        create<ast::ReturnStatement>(),
-    });
-    auto* func = create<ast::Function>(
-        mod->RegisterSymbol("b"), "b", params, ty.void_, body,
-        ast::FunctionDecorationList{
-            create<ast::StageDecoration>(ast::PipelineStage::kCompute),
-        });
+    auto* func =
+        Func("b", ast::VariableList{}, ty.void_,
+             ast::StatementList{
+                 create<ast::VariableDeclStatement>(var),
+                 create<ast::ReturnStatement>(),
+             },
+             ast::FunctionDecorationList{
+                 create<ast::StageDecoration>(ast::PipelineStage::kCompute),
+             });
 
     mod->AddFunction(func);
   }
diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc
index abc82a7..0bdd97f 100644
--- a/src/writer/wgsl/generator_impl_test.cc
+++ b/src/writer/wgsl/generator_impl_test.cc
@@ -32,10 +32,8 @@
 TEST_F(WgslGeneratorImplTest, Generate) {
   ast::type::Void void_type;
 
-  mod->AddFunction(create<ast::Function>(
-      mod->RegisterSymbol("a_func"), "my_func", ast::VariableList{}, &void_type,
-      create<ast::BlockStatement>(ast::StatementList{}),
-      ast::FunctionDecorationList{}));
+  mod->AddFunction(Func("my_func", ast::VariableList{}, &void_type,
+                        ast::StatementList{}, ast::FunctionDecorationList{}));
 
   ASSERT_TRUE(gen.Generate(*mod)) << gen.error();
   EXPECT_EQ(gen.result(), R"(fn my_func() -> void {