Remove BlockStatement::append()

Bug: tint:396
Bug: tint:390
Change-Id: I3b558a8961f9890f24d1aa3d6647ec095e5fe1cb
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35421
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/block_statement.cc b/src/ast/block_statement.cc
index d952a22..cbaa0a6 100644
--- a/src/ast/block_statement.cc
+++ b/src/ast/block_statement.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-BlockStatement::BlockStatement(const Source& source) : Base(source) {}
-
 BlockStatement::BlockStatement(const Source& source,
                                const StatementList& statements)
     : Base(source), statements_(std::move(statements)) {}
@@ -33,9 +31,8 @@
 BlockStatement::~BlockStatement() = default;
 
 BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
-  auto* cloned = ctx->mod->create<BlockStatement>(ctx->Clone(source()));
-  cloned->statements_ = ctx->Clone(statements_);
-  return cloned;
+  return ctx->mod->create<BlockStatement>(ctx->Clone(source()),
+                                          ctx->Clone(statements_));
 }
 
 bool BlockStatement::IsValid() const {
diff --git a/src/ast/block_statement.h b/src/ast/block_statement.h
index 730f7bf..9b5417a 100644
--- a/src/ast/block_statement.h
+++ b/src/ast/block_statement.h
@@ -29,19 +29,12 @@
  public:
   /// Constructor
   /// @param source the block statement source
-  explicit BlockStatement(const Source& source);
-  /// Constructor
-  /// @param source the block statement source
-  /// @param statements the block statements
+  /// @param statements the statements
   BlockStatement(const Source& source, const StatementList& statements);
   /// Move constructor
   BlockStatement(BlockStatement&&);
   ~BlockStatement() override;
 
-  /// Appends a statement to the block
-  /// @param stmt the statement to append
-  void append(Statement* stmt) { statements_.push_back(stmt); }
-
   /// Insert a statement to the block
   /// @param index the index to insert at
   /// @param stmt the statement to insert
@@ -79,13 +72,9 @@
   const Statement* operator[](size_t idx) const { return statements_[idx]; }
 
   /// @returns the beginning iterator
-  std::vector<Statement*>::const_iterator begin() const {
-    return statements_.begin();
-  }
+  StatementList::const_iterator begin() const { return statements_.begin(); }
   /// @returns the ending iterator
-  std::vector<Statement*>::const_iterator end() const {
-    return statements_.end();
-  }
+  StatementList::const_iterator end() const { return statements_.end(); }
 
   /// Clones this node and all transitive child nodes using the `CloneContext`
   /// `ctx`.
@@ -106,7 +95,7 @@
  private:
   BlockStatement(const BlockStatement&) = delete;
 
-  std::vector<Statement*> statements_;
+  StatementList statements_;
 };
 
 }  // namespace ast
diff --git a/src/ast/block_statement_test.cc b/src/ast/block_statement_test.cc
index 086931c..71b71d2 100644
--- a/src/ast/block_statement_test.cc
+++ b/src/ast/block_statement_test.cc
@@ -31,8 +31,7 @@
   auto* d = create<DiscardStatement>(Source{});
   auto* ptr = d;
 
-  BlockStatement b(Source{});
-  b.append(d);
+  BlockStatement b(Source{}, StatementList{d});
 
   ASSERT_EQ(b.size(), 1u);
   EXPECT_EQ(b[0], ptr);
@@ -43,7 +42,7 @@
   auto* s2 = create<DiscardStatement>(Source{});
   auto* s3 = create<DiscardStatement>(Source{});
 
-  BlockStatement b(Source{});
+  BlockStatement b(Source{}, StatementList{});
   b.insert(0, s1);
   b.insert(0, s2);
   b.insert(1, s3);
@@ -57,46 +56,53 @@
 }
 
 TEST_F(BlockStatementTest, Creation_WithSource) {
-  BlockStatement b(Source{Source::Location{20, 2}});
+  BlockStatement b(Source{Source::Location{20, 2}}, ast::StatementList{});
   auto src = b.source();
   EXPECT_EQ(src.range.begin.line, 20u);
   EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(BlockStatementTest, IsBlock) {
-  BlockStatement b(Source{});
+  BlockStatement b(Source{}, ast::StatementList{});
   EXPECT_TRUE(b.Is<BlockStatement>());
 }
 
 TEST_F(BlockStatementTest, IsValid) {
-  BlockStatement b(Source{});
-  b.append(create<DiscardStatement>(Source{}));
+  BlockStatement b(Source{}, ast::StatementList{
+                                 create<DiscardStatement>(Source{}),
+                             });
   EXPECT_TRUE(b.IsValid());
 }
 
 TEST_F(BlockStatementTest, IsValid_Empty) {
-  BlockStatement b(Source{});
+  BlockStatement b(Source{}, ast::StatementList{});
   EXPECT_TRUE(b.IsValid());
 }
 
 TEST_F(BlockStatementTest, IsValid_NullBodyStatement) {
-  BlockStatement b(Source{});
-  b.append(create<DiscardStatement>(Source{}));
-  b.append(nullptr);
+  BlockStatement b(Source{}, ast::StatementList{
+                                 create<DiscardStatement>(Source{}),
+                                 nullptr,
+                             });
+
   EXPECT_FALSE(b.IsValid());
 }
 
 TEST_F(BlockStatementTest, IsValid_InvalidBodyStatement) {
-  BlockStatement b(Source{});
-  b.append(create<IfStatement>(Source{}, nullptr,
-                               create<BlockStatement>(Source{}),
-                               ElseStatementList{}));
+  BlockStatement b(
+      Source{},
+      ast::StatementList{
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ElseStatementList{}),
+      });
   EXPECT_FALSE(b.IsValid());
 }
 
 TEST_F(BlockStatementTest, ToStr) {
-  BlockStatement b(Source{});
-  b.append(create<DiscardStatement>(Source{}));
+  BlockStatement b(Source{}, ast::StatementList{
+                                 create<DiscardStatement>(Source{}),
+                             });
 
   std::ostringstream out;
   b.to_str(out, 2);
diff --git a/src/ast/case_statement_test.cc b/src/ast/case_statement_test.cc
index 0473418..95714ad 100644
--- a/src/ast/case_statement_test.cc
+++ b/src/ast/case_statement_test.cc
@@ -35,9 +35,8 @@
   auto* selector = create<SintLiteral>(Source{}, &i32, 2);
   b.push_back(selector);
 
-  auto* body = create<BlockStatement>(Source{});
   auto* discard = create<DiscardStatement>(Source{});
-  body->append(discard);
+  auto* body = create<BlockStatement>(Source{}, StatementList{discard});
 
   CaseStatement c(Source{}, b, body);
   ASSERT_EQ(c.selectors().size(), 1u);
@@ -53,9 +52,8 @@
   auto* selector = create<SintLiteral>(Source{}, &u32, 2);
   b.push_back(selector);
 
-  auto* body = create<BlockStatement>(Source{});
   auto* discard = create<DiscardStatement>(Source{});
-  body->append(discard);
+  auto* body = create<BlockStatement>(Source{}, StatementList{discard});
 
   CaseStatement c(Source{}, b, body);
   ASSERT_EQ(c.selectors().size(), 1u);
@@ -69,9 +67,10 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{Source::Location{20, 2}}, b, body);
   auto src = c.source();
   EXPECT_EQ(src.range.begin.line, 20u);
@@ -79,9 +78,10 @@
 }
 
 TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{}, CaseSelectorList{}, body);
   EXPECT_TRUE(c.IsDefault());
 }
@@ -91,19 +91,20 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
-  CaseStatement c(Source{}, b, create<BlockStatement>(Source{}));
+  CaseStatement c(Source{}, b,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_FALSE(c.IsDefault());
 }
 
 TEST_F(CaseStatementTest, IsCase) {
   CaseStatement c(Source{}, CaseSelectorList{},
-                  create<BlockStatement>(Source{}));
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(c.Is<CaseStatement>());
 }
 
 TEST_F(CaseStatementTest, IsValid) {
   CaseStatement c(Source{}, CaseSelectorList{},
-                  create<BlockStatement>(Source{}));
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(c.IsValid());
 }
 
@@ -112,10 +113,11 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
   CaseStatement c(Source{}, b, body);
   EXPECT_FALSE(c.IsValid());
 }
@@ -125,11 +127,13 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<IfStatement>(Source{}, nullptr,
-                                   create<BlockStatement>(Source{}),
-                                   ElseStatementList{}));
-
+  auto* body = create<BlockStatement>(
+      Source{},
+      StatementList{
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ElseStatementList{}),
+      });
   CaseStatement c(Source{}, {b}, body);
   EXPECT_FALSE(c.IsValid());
 }
@@ -139,8 +143,10 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(Source{}, &i32, -2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{}, {b}, body);
 
   std::ostringstream out;
@@ -156,8 +162,10 @@
   CaseSelectorList b;
   b.push_back(create<UintLiteral>(Source{}, &u32, 2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{}, {b}, body);
 
   std::ostringstream out;
@@ -175,8 +183,10 @@
   b.push_back(create<SintLiteral>(Source{}, &i32, 1));
   b.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{}, b, body);
 
   std::ostringstream out;
@@ -188,8 +198,10 @@
 }
 
 TEST_F(CaseStatementTest, ToStr_WithoutSelectors) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   CaseStatement c(Source{}, CaseSelectorList{}, body);
 
   std::ostringstream out;
diff --git a/src/ast/else_statement_test.cc b/src/ast/else_statement_test.cc
index c2ea1e8..f1b681c 100644
--- a/src/ast/else_statement_test.cc
+++ b/src/ast/else_statement_test.cc
@@ -31,9 +31,10 @@
   type::Bool bool_type;
   auto* cond = create<ScalarConstructorExpression>(
       Source{}, create<BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   auto* discard = body->get(0);
 
   ElseStatement e(Source{}, cond, body);
@@ -44,14 +45,15 @@
 
 TEST_F(ElseStatementTest, Creation_WithSource) {
   ElseStatement e(Source{Source::Location{20, 2}}, nullptr,
-                  create<BlockStatement>(Source{}));
+                  create<BlockStatement>(Source{}, StatementList{}));
   auto src = e.source();
   EXPECT_EQ(src.range.begin.line, 20u);
   EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(ElseStatementTest, IsElse) {
-  ElseStatement e(Source{}, nullptr, create<BlockStatement>(Source{}));
+  ElseStatement e(Source{}, nullptr,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(e.Is<ElseStatement>());
 }
 
@@ -59,49 +61,57 @@
   type::Bool bool_type;
   auto* cond = create<ScalarConstructorExpression>(
       Source{}, create<BoolLiteral>(Source{}, &bool_type, true));
-  ElseStatement e(Source{}, cond, create<BlockStatement>(Source{}));
+  ElseStatement e(Source{}, cond,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(e.HasCondition());
 }
 
 TEST_F(ElseStatementTest, HasContition_NullCondition) {
-  ElseStatement e(Source{}, nullptr, create<BlockStatement>(Source{}));
+  ElseStatement e(Source{}, nullptr,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_FALSE(e.HasCondition());
 }
 
 TEST_F(ElseStatementTest, IsValid) {
-  ElseStatement e(Source{}, nullptr, create<BlockStatement>(Source{}));
+  ElseStatement e(Source{}, nullptr,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(e.IsValid());
 }
 
 TEST_F(ElseStatementTest, IsValid_WithBody) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   ElseStatement e(Source{}, nullptr, body);
   EXPECT_TRUE(e.IsValid());
 }
 
 TEST_F(ElseStatementTest, IsValid_WithNullBodyStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
   ElseStatement e(Source{}, nullptr, body);
   EXPECT_FALSE(e.IsValid());
 }
 
 TEST_F(ElseStatementTest, IsValid_InvalidCondition) {
   auto* cond = create<ScalarConstructorExpression>(Source{}, nullptr);
-  ElseStatement e(Source{}, cond, create<BlockStatement>(Source{}));
+  ElseStatement e(Source{}, cond,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_FALSE(e.IsValid());
 }
 
 TEST_F(ElseStatementTest, IsValid_InvalidBodyStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<IfStatement>(Source{}, nullptr,
-                                   create<BlockStatement>(Source{}),
-                                   ElseStatementList{}));
-
+  auto* body = create<BlockStatement>(
+      Source{},
+      StatementList{
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ElseStatementList{}),
+      });
   ElseStatement e(Source{}, nullptr, body);
   EXPECT_FALSE(e.IsValid());
 }
@@ -110,9 +120,10 @@
   type::Bool bool_type;
   auto* cond = create<ScalarConstructorExpression>(
       Source{}, create<BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   ElseStatement e(Source{}, cond, body);
   std::ostringstream out;
   e.to_str(out, 2);
@@ -128,9 +139,10 @@
 }
 
 TEST_F(ElseStatementTest, ToStr_NoCondition) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   ElseStatement e(Source{}, nullptr, body);
   std::ostringstream out;
   e.to_str(out, 2);
diff --git a/src/ast/function_test.cc b/src/ast/function_test.cc
index f3439cc..546e969 100644
--- a/src/ast/function_test.cc
+++ b/src/ast/function_test.cc
@@ -44,7 +44,8 @@
   auto* var = params[0];
 
   Function f(Source{}, func_sym, "func", params, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_EQ(f.symbol(), func_sym);
   EXPECT_EQ(f.name(), "func");
   ASSERT_EQ(f.params().size(), 1u);
@@ -64,7 +65,7 @@
                                     ast::VariableDecorationList{}));
 
   Function f(Source{Source::Location{20, 2}}, func_sym, "func", params,
-             &void_type, create<BlockStatement>(Source{}),
+             &void_type, create<BlockStatement>(Source{}, StatementList{}),
              FunctionDecorationList{});
   auto src = f.source();
   EXPECT_EQ(src.range.begin.line, 20u);
@@ -80,7 +81,8 @@
   Variable v(Source{}, "var", StorageClass::kInput, &i32, false, nullptr,
              ast::VariableDecorationList{});
   Function f(Source{}, func_sym, "func", VariableList{}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
 
   f.add_referenced_module_variable(&v);
   ASSERT_EQ(f.referenced_module_variables().size(), 1u);
@@ -127,7 +129,8 @@
       });
 
   Function f(Source{}, func_sym, "func", VariableList{}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
 
   f.add_referenced_module_variable(loc1);
   f.add_referenced_module_variable(builtin1);
@@ -174,7 +177,8 @@
       });
 
   Function f(Source{}, func_sym, "func", VariableList{}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
 
   f.add_referenced_module_variable(loc1);
   f.add_referenced_module_variable(builtin1);
@@ -197,7 +201,8 @@
   auto main_sym = mod.RegisterSymbol("main");
 
   Function f(Source{}, func_sym, "func", VariableList{}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
 
   f.add_ancestor_entry_point(main_sym);
   ASSERT_EQ(1u, f.ancestor_entry_points().size());
@@ -219,8 +224,10 @@
                                     false, nullptr,
                                     ast::VariableDecorationList{}));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
 
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
@@ -238,10 +245,8 @@
                                     false, nullptr,
                                     ast::VariableDecorationList{}));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
-  Function f(Source{}, func_sym, "", params, &void_type, body,
+  Function f(Source{}, func_sym, "", params, &void_type,
+             create<BlockStatement>(Source{}, StatementList{}),
              FunctionDecorationList{});
   EXPECT_FALSE(f.IsValid());
 }
@@ -257,7 +262,8 @@
                                     ast::VariableDecorationList{}));
 
   Function f(Source{}, func_sym, "func", params, nullptr,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_FALSE(f.IsValid());
 }
 
@@ -274,7 +280,8 @@
   params.push_back(nullptr);
 
   Function f(Source{}, func_sym, "func", params, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_FALSE(f.IsValid());
 }
 
@@ -289,7 +296,8 @@
                                     ast::VariableDecorationList{}));
 
   Function f(Source{}, func_sym, "func", params, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_FALSE(f.IsValid());
 }
 
@@ -304,9 +312,11 @@
                                     false, nullptr,
                                     ast::VariableDecorationList{}));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
 
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
@@ -325,9 +335,11 @@
                                     false, nullptr,
                                     ast::VariableDecorationList{}));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
 
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
@@ -340,8 +352,10 @@
 
   auto func_sym = mod.RegisterSymbol("func");
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
 
   Function f(Source{}, func_sym, "func", {}, &void_type, body,
              FunctionDecorationList{});
@@ -362,9 +376,10 @@
 
   auto func_sym = mod.RegisterSymbol("func");
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   Function f(
       Source{}, func_sym, "func", {}, &void_type, body,
       FunctionDecorationList{create<WorkgroupDecoration>(2, 4, 6, Source{})});
@@ -391,9 +406,10 @@
                                     false, nullptr,
                                     ast::VariableDecorationList{}));
 
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                       });
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
 
@@ -419,7 +435,8 @@
   auto func_sym = mod.RegisterSymbol("func");
 
   Function f(Source{}, func_sym, "func", {}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_EQ(f.type_name(), "__func__void");
 }
 
@@ -439,7 +456,8 @@
                                     ast::VariableDecorationList{}));
 
   Function f(Source{}, func_sym, "func", params, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   EXPECT_EQ(f.type_name(), "__func__void__i32__f32");
 }
 
@@ -449,9 +467,8 @@
   auto func_sym = mod.RegisterSymbol("func");
 
   VariableList params;
-  auto* body = create<BlockStatement>(Source{});
   auto* stmt = create<DiscardStatement>(Source{});
-  body->append(stmt);
+  auto* body = create<BlockStatement>(Source{}, StatementList{stmt});
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
 
@@ -464,7 +481,7 @@
   auto func_sym = mod.RegisterSymbol("func");
 
   VariableList params;
-  auto* body = create<BlockStatement>(Source{});
+  auto* body = create<BlockStatement>(Source{}, StatementList{});
   Function f(Source{}, func_sym, "func", params, &void_type, body,
              FunctionDecorationList{});
 
@@ -477,7 +494,8 @@
   auto func_sym = mod.RegisterSymbol("func");
 
   Function f(Source{}, func_sym, "func", {}, &void_type,
-             create<BlockStatement>(Source{}), FunctionDecorationList{});
+             create<BlockStatement>(Source{}, StatementList{}),
+             FunctionDecorationList{});
   uint32_t x = 0;
   uint32_t y = 0;
   uint32_t z = 0;
@@ -493,7 +511,7 @@
   auto func_sym = mod.RegisterSymbol("func");
 
   Function f(Source{}, func_sym, "func", {}, &void_type,
-             create<BlockStatement>(Source{}),
+             create<BlockStatement>(Source{}, StatementList{}),
              {create<WorkgroupDecoration>(2u, 4u, 6u, Source{})});
 
   uint32_t x = 0;
diff --git a/src/ast/if_statement_test.cc b/src/ast/if_statement_test.cc
index 7c7c777..250c145 100644
--- a/src/ast/if_statement_test.cc
+++ b/src/ast/if_statement_test.cc
@@ -27,9 +27,8 @@
 TEST_F(IfStatementTest, Creation) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{Source::Location{20, 2}}, cond, body,
                    ElseStatementList{});
   auto src = stmt.source();
@@ -38,7 +37,8 @@
 }
 
 TEST_F(IfStatementTest, IsIf) {
-  IfStatement stmt(Source{}, nullptr, create<BlockStatement>(Source{}),
+  IfStatement stmt(Source{}, nullptr,
+                   create<BlockStatement>(Source{}, StatementList{}),
                    ElseStatementList{});
   EXPECT_TRUE(stmt.Is<IfStatement>());
 }
@@ -46,9 +46,8 @@
 TEST_F(IfStatementTest, IsValid) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body, ElseStatementList{});
   EXPECT_TRUE(stmt.IsValid());
 }
@@ -56,26 +55,25 @@
 TEST_F(IfStatementTest, IsValid_WithElseStatements) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body,
                    {
                        create<ElseStatement>(
                            Source{},
                            create<IdentifierExpression>(
                                Source{}, mod.RegisterSymbol("Ident"), "Ident"),
-                           create<BlockStatement>(Source{})),
-                       create<ElseStatement>(Source{}, nullptr,
-                                             create<BlockStatement>(Source{})),
+                           create<BlockStatement>(Source{}, StatementList{})),
+                       create<ElseStatement>(
+                           Source{}, nullptr,
+                           create<BlockStatement>(Source{}, StatementList{})),
                    });
   EXPECT_TRUE(stmt.IsValid());
 }
 
 TEST_F(IfStatementTest, IsValid_MissingCondition) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, nullptr, body, ElseStatementList{});
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -83,9 +81,8 @@
 TEST_F(IfStatementTest, IsValid_InvalidCondition) {
   auto* cond =
       create<IdentifierExpression>(Source{}, mod.RegisterSymbol(""), "");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body, ElseStatementList{});
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -93,10 +90,11 @@
 TEST_F(IfStatementTest, IsValid_NullBodyStatement) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
-
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
   IfStatement stmt(Source{}, cond, body, ElseStatementList{});
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -104,12 +102,14 @@
 TEST_F(IfStatementTest, IsValid_InvalidBodyStatement) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(create<IfStatement>(Source{}, nullptr,
-                                   create<BlockStatement>(Source{}),
-                                   ast::ElseStatementList{}));
-
+  auto* body = create<BlockStatement>(
+      Source{},
+      StatementList{
+          create<DiscardStatement>(Source{}),
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ast::ElseStatementList{}),
+      });
   IfStatement stmt(Source{}, cond, body, ElseStatementList{});
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -117,18 +117,18 @@
 TEST_F(IfStatementTest, IsValid_NullElseStatement) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body,
                    {
                        create<ElseStatement>(
                            Source{},
                            create<IdentifierExpression>(
                                Source{}, mod.RegisterSymbol("Ident"), "Ident"),
-                           create<BlockStatement>(Source{})),
-                       create<ElseStatement>(Source{}, nullptr,
-                                             create<BlockStatement>(Source{})),
+                           create<BlockStatement>(Source{}, StatementList{})),
+                       create<ElseStatement>(
+                           Source{}, nullptr,
+                           create<BlockStatement>(Source{}, StatementList{})),
                        nullptr,
                    });
   EXPECT_FALSE(stmt.IsValid());
@@ -137,32 +137,32 @@
 TEST_F(IfStatementTest, IsValid_InvalidElseStatement) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
-  IfStatement stmt(
-      Source{}, cond, body,
-      {
-          create<ElseStatement>(Source{},
-                                create<IdentifierExpression>(
-                                    Source{}, mod.RegisterSymbol(""), ""),
-                                create<BlockStatement>(Source{})),
-      });
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
+  IfStatement stmt(Source{}, cond, body,
+                   {
+                       create<ElseStatement>(
+                           Source{},
+                           create<IdentifierExpression>(
+                               Source{}, mod.RegisterSymbol(""), ""),
+                           create<BlockStatement>(Source{}, StatementList{})),
+                   });
   EXPECT_FALSE(stmt.IsValid());
 }
 
 TEST_F(IfStatementTest, IsValid_MultipleElseWiththoutCondition) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body,
                    {
-                       create<ElseStatement>(Source{}, nullptr,
-                                             create<BlockStatement>(Source{})),
-                       create<ElseStatement>(Source{}, nullptr,
-                                             create<BlockStatement>(Source{})),
+                       create<ElseStatement>(
+                           Source{}, nullptr,
+                           create<BlockStatement>(Source{}, StatementList{})),
+                       create<ElseStatement>(
+                           Source{}, nullptr,
+                           create<BlockStatement>(Source{}, StatementList{})),
                    });
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -170,18 +170,18 @@
 TEST_F(IfStatementTest, IsValid_ElseNotLast) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body,
                    {
-                       create<ElseStatement>(Source{}, nullptr,
-                                             create<BlockStatement>(Source{})),
+                       create<ElseStatement>(
+                           Source{}, nullptr,
+                           create<BlockStatement>(Source{}, StatementList{})),
                        create<ElseStatement>(
                            Source{},
                            create<IdentifierExpression>(
-                               Source{}, mod.RegisterSymbol("ident"), "ident"),
-                           create<BlockStatement>(Source{})),
+                               Source{}, mod.RegisterSymbol("Ident"), "Ident"),
+                           create<BlockStatement>(Source{}, StatementList{})),
                    });
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -189,9 +189,8 @@
 TEST_F(IfStatementTest, ToStr) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body, ElseStatementList{});
 
   std::ostringstream out;
@@ -210,16 +209,13 @@
 TEST_F(IfStatementTest, ToStr_WithElseStatements) {
   auto* cond = create<IdentifierExpression>(Source{},
                                             mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-
-  auto* else_if_body = create<BlockStatement>(Source{});
-  else_if_body->append(create<DiscardStatement>(Source{}));
-
-  auto* else_body = create<BlockStatement>(Source{});
-  else_body->append(create<DiscardStatement>(Source{}));
-  else_body->append(create<DiscardStatement>(Source{}));
-
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
+  auto* else_if_body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
+  auto* else_body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{}),
+                              create<DiscardStatement>(Source{})});
   IfStatement stmt(Source{}, cond, body,
                    {
                        create<ElseStatement>(
diff --git a/src/ast/loop_statement_test.cc b/src/ast/loop_statement_test.cc
index 4588d01..58e4b79 100644
--- a/src/ast/loop_statement_test.cc
+++ b/src/ast/loop_statement_test.cc
@@ -28,12 +28,12 @@
 using LoopStatementTest = TestHelper;
 
 TEST_F(LoopStatementTest, Creation) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
   auto* b = body->last();
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   ASSERT_EQ(l.body()->size(), 1u);
@@ -43,11 +43,11 @@
 }
 
 TEST_F(LoopStatementTest, Creation_WithSource) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{Source::Location{20, 2}}, body, continuing);
   auto src = l.source();
@@ -56,110 +56,121 @@
 }
 
 TEST_F(LoopStatementTest, IsLoop) {
-  LoopStatement l(Source{}, create<BlockStatement>(Source{}),
-                  create<BlockStatement>(Source{}));
+  LoopStatement l(Source{}, create<BlockStatement>(Source{}, StatementList{}),
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(l.Is<LoopStatement>());
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithoutContinuing) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, {});
   EXPECT_FALSE(l.has_continuing());
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithContinuing) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_TRUE(l.has_continuing());
 }
 
 TEST_F(LoopStatementTest, IsValid) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_WithoutContinuing) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  LoopStatement l(Source{}, body, create<BlockStatement>(Source{}));
+  LoopStatement l(Source{}, body,
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_WithoutBody) {
-  LoopStatement l(Source{}, create<BlockStatement>(Source{}),
-                  create<BlockStatement>(Source{}));
+  LoopStatement l(Source{}, create<BlockStatement>(Source{}, StatementList{}),
+                  create<BlockStatement>(Source{}, StatementList{}));
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_NullBodyStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(nullptr);
+  auto* body =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_InvalidBodyStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
-  body->append(create<IfStatement>(Source{}, nullptr,
-                                   create<BlockStatement>(Source{}),
-                                   ElseStatementList{}));
+  auto* body = create<BlockStatement>(
+      Source{},
+      StatementList{
+          create<DiscardStatement>(Source{}),
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ElseStatementList{}),
+      });
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_NullContinuingStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
-  continuing->append(nullptr);
+  auto* continuing =
+      create<BlockStatement>(Source{}, StatementList{
+                                           create<DiscardStatement>(Source{}),
+                                           nullptr,
+                                       });
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_InvalidContinuingStatement) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
-  continuing->append(create<IfStatement>(Source{}, nullptr,
-                                         create<BlockStatement>(Source{}),
-                                         ElseStatementList{}));
+  auto* continuing = create<BlockStatement>(
+      Source{},
+      StatementList{
+          create<DiscardStatement>(Source{}),
+          create<IfStatement>(Source{}, nullptr,
+                              create<BlockStatement>(Source{}, StatementList{}),
+                              ElseStatementList{}),
+      });
 
   LoopStatement l(Source{}, body, continuing);
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, ToStr) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, {});
   std::ostringstream out;
@@ -171,11 +182,11 @@
 }
 
 TEST_F(LoopStatementTest, ToStr_WithContinuing) {
-  auto* body = create<BlockStatement>(Source{});
-  body->append(create<DiscardStatement>(Source{}));
+  auto* body = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
-  auto* continuing = create<BlockStatement>(Source{});
-  continuing->append(create<DiscardStatement>(Source{}));
+  auto* continuing = create<BlockStatement>(
+      Source{}, StatementList{create<DiscardStatement>(Source{})});
 
   LoopStatement l(Source{}, body, continuing);
   std::ostringstream out;
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
index 75a4d3c..03be7eb 100644
--- a/src/ast/module_test.cc
+++ b/src/ast/module_test.cc
@@ -49,9 +49,10 @@
   Module m;
 
   auto func_sym = m.RegisterSymbol("main");
-  auto* func = create<Function>(Source{}, func_sym, "main", VariableList{},
-                                &f32, create<BlockStatement>(Source{}),
-                                ast::FunctionDecorationList{});
+  auto* func =
+      create<Function>(Source{}, func_sym, "main", VariableList{}, &f32,
+                       create<BlockStatement>(Source{}, StatementList{}),
+                       ast::FunctionDecorationList{});
   m.AddFunction(func);
   EXPECT_EQ(func, m.FindFunctionBySymbol(func_sym));
 }
@@ -133,7 +134,9 @@
 
   auto* func = create<Function>(
       Source{}, m.RegisterSymbol("main"), "main", VariableList(), &f32,
-      create<BlockStatement>(Source{}), ast::FunctionDecorationList{});
+      create<BlockStatement>(Source{}, StatementList{}),
+      ast::FunctionDecorationList{});
+
   m.AddFunction(func);
   EXPECT_TRUE(m.IsValid());
 }
diff --git a/src/ast/switch_statement_test.cc b/src/ast/switch_statement_test.cc
index 9a73e39..bb5ce31 100644
--- a/src/ast/switch_statement_test.cc
+++ b/src/ast/switch_statement_test.cc
@@ -37,8 +37,8 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
   CaseStatementList body;
-  auto* case_stmt =
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{}));
+  auto* case_stmt = create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{}));
   body.push_back(case_stmt);
 
   SwitchStatement stmt(Source{}, ident, body);
@@ -67,8 +67,8 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
 
   SwitchStatement stmt(Source{}, ident, body);
   EXPECT_TRUE(stmt.Is<SwitchStatement>());
@@ -83,8 +83,8 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
 
   SwitchStatement stmt(Source{}, ident, body);
   EXPECT_TRUE(stmt.IsValid());
@@ -97,8 +97,8 @@
   lit.push_back(create<SintLiteral>(Source{}, &i32, 2));
 
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
 
   SwitchStatement stmt(Source{}, nullptr, body);
   EXPECT_FALSE(stmt.IsValid());
@@ -113,8 +113,8 @@
   auto* ident =
       create<IdentifierExpression>(Source{}, mod.RegisterSymbol(""), "");
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
 
   SwitchStatement stmt(Source{}, ident, body);
   EXPECT_FALSE(stmt.IsValid());
@@ -129,8 +129,8 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
   body.push_back(nullptr);
 
   SwitchStatement stmt(Source{}, ident, body);
@@ -141,9 +141,9 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
 
-  auto* case_body = create<BlockStatement>(Source{});
-  case_body->append(nullptr);
-
+  auto* case_body = create<BlockStatement>(Source{}, StatementList{
+                                                         nullptr,
+                                                     });
   CaseStatementList body;
   body.push_back(
       create<CaseStatement>(Source{}, CaseSelectorList{}, case_body));
@@ -176,8 +176,8 @@
   auto* ident = create<IdentifierExpression>(
       Source{}, mod.RegisterSymbol("ident"), "ident");
   CaseStatementList body;
-  body.push_back(
-      create<CaseStatement>(Source{}, lit, create<BlockStatement>(Source{})));
+  body.push_back(create<CaseStatement>(
+      Source{}, lit, create<BlockStatement>(Source{}, StatementList{})));
 
   SwitchStatement stmt(Source{}, ident, body);
   std::ostringstream out;
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 2341b84..d149929 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -81,8 +81,10 @@
   ast::Function* MakeEmptyBodyFunction(
       std::string name,
       ast::FunctionDecorationList decorations = {}) {
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::ReturnStatement>(Source{}));
+    auto* body = create<ast::BlockStatement>(
+        Source{}, ast::StatementList{
+                      create<ast::ReturnStatement>(Source{}),
+                  });
     return create<ast::Function>(Source{}, mod()->RegisterSymbol(name), name,
                                  ast::VariableList(), void_type(), body,
                                  decorations);
@@ -97,13 +99,15 @@
       std::string caller,
       std::string callee,
       ast::FunctionDecorationList decorations = {}) {
-    auto* body = create<ast::BlockStatement>(Source{});
     auto* ident_expr = create<ast::IdentifierExpression>(
         Source{}, mod()->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    body->append(create<ast::CallStatement>(Source{}, call_expr));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(), body,
                                  decorations);
@@ -148,18 +152,19 @@
       std::string name,
       std::vector<std::tuple<std::string, std::string>> inout_vars,
       ast::FunctionDecorationList decorations = {}) {
-    auto* body = create<ast::BlockStatement>(Source{});
+    ast::StatementList stmts;
     for (auto inout : inout_vars) {
       std::string in, out;
       std::tie(in, out) = inout;
-      body->append(create<ast::AssignmentStatement>(
+      stmts.emplace_back(create<ast::AssignmentStatement>(
           Source{},
           create<ast::IdentifierExpression>(Source{},
                                             mod()->RegisterSymbol(out), out),
           create<ast::IdentifierExpression>(Source{}, mod()->RegisterSymbol(in),
                                             in)));
     }
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(), body,
                                  decorations);
@@ -178,11 +183,11 @@
       std::string callee,
       std::vector<std::tuple<std::string, std::string>> inout_vars,
       ast::FunctionDecorationList decorations = {}) {
-    auto* body = create<ast::BlockStatement>(Source{});
+    ast::StatementList stmts;
     for (auto inout : inout_vars) {
       std::string in, out;
       std::tie(in, out) = inout;
-      body->append(create<ast::AssignmentStatement>(
+      stmts.emplace_back(create<ast::AssignmentStatement>(
           Source{},
           create<ast::IdentifierExpression>(Source{},
                                             mod()->RegisterSymbol(out), out),
@@ -193,8 +198,9 @@
         Source{}, mod()->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    body->append(create<ast::CallStatement>(Source{}, call_expr));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(), body,
                                  decorations);
@@ -428,14 +434,13 @@
       std::string func_name,
       std::string struct_name,
       std::vector<std::tuple<size_t, ast::type::Type*>> members) {
-    auto* body = create<ast::BlockStatement>(Source{});
-
+    ast::StatementList stmts;
     for (auto member : members) {
       size_t member_idx;
       ast::type::Type* member_type;
       std::tie(member_idx, member_type) = member;
       std::string member_name = StructMemberName(member_idx, member_type);
-      body->append(create<ast::VariableDeclStatement>(
+      stmts.emplace_back(create<ast::VariableDeclStatement>(
           Source{}, create<ast::Variable>(
                         Source{},                          // source
                         "local" + member_name,             // name
@@ -451,7 +456,7 @@
       ast::type::Type* member_type;
       std::tie(member_idx, member_type) = member;
       std::string member_name = StructMemberName(member_idx, member_type);
-      body->append(create<ast::AssignmentStatement>(
+      stmts.emplace_back(create<ast::AssignmentStatement>(
           Source{},
           create<ast::IdentifierExpression>(
               Source{}, mod()->RegisterSymbol("local" + member_name),
@@ -464,7 +469,8 @@
                   Source{}, mod()->RegisterSymbol(member_name), member_name))));
     }
 
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(),
                                  body, ast::FunctionDecorationList{});
@@ -584,8 +590,7 @@
       ast::FunctionDecorationList decorations = {}) {
     std::string result_name = "sampler_result";
 
-    auto* body = create<ast::BlockStatement>(Source{});
-
+    ast::StatementList stmts;
     auto* call_result =
         create<ast::Variable>(Source{},                        // source
                               "sampler_result",                // name
@@ -594,7 +599,8 @@
                               false,                           // is_const
                               nullptr,                         // constructor
                               ast::VariableDecorationList{});  // decorations
-    body->append(create<ast::VariableDeclStatement>(Source{}, call_result));
+    stmts.emplace_back(
+        create<ast::VariableDeclStatement>(Source{}, call_result));
 
     ast::ExpressionList call_params;
     call_params.push_back(create<ast::IdentifierExpression>(
@@ -609,14 +615,15 @@
             Source{}, mod()->RegisterSymbol("textureSample"), "textureSample"),
         call_params);
 
-    body->append(create<ast::AssignmentStatement>(
+    stmts.emplace_back(create<ast::AssignmentStatement>(
         Source{},
         create<ast::IdentifierExpression>(
             Source{}, mod()->RegisterSymbol("sampler_result"),
             "sampler_result"),
         call_expr));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(),
                                  body, decorations);
@@ -641,7 +648,7 @@
       ast::FunctionDecorationList decorations = {}) {
     std::string result_name = "sampler_result";
 
-    auto* body = create<ast::BlockStatement>(Source{});
+    ast::StatementList stmts;
 
     auto* call_result =
         create<ast::Variable>(Source{},                        // source
@@ -651,7 +658,8 @@
                               false,                           // is_const
                               nullptr,                         // constructor
                               ast::VariableDecorationList{});  // decorations
-    body->append(create<ast::VariableDeclStatement>(Source{}, call_result));
+    stmts.emplace_back(
+        create<ast::VariableDeclStatement>(Source{}, call_result));
 
     ast::ExpressionList call_params;
     call_params.push_back(create<ast::IdentifierExpression>(
@@ -668,14 +676,15 @@
             Source{}, mod()->RegisterSymbol("textureSample"), "textureSample"),
         call_params);
 
-    body->append(create<ast::AssignmentStatement>(
+    stmts.emplace_back(create<ast::AssignmentStatement>(
         Source{},
         create<ast::IdentifierExpression>(
             Source{}, mod()->RegisterSymbol("sampler_result"),
             "sampler_result"),
         call_expr));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(),
                                  body, decorations);
@@ -701,7 +710,7 @@
       ast::FunctionDecorationList decorations = {}) {
     std::string result_name = "sampler_result";
 
-    auto* body = create<ast::BlockStatement>(Source{});
+    ast::StatementList stmts;
 
     auto* call_result =
         create<ast::Variable>(Source{},                        // source
@@ -711,7 +720,8 @@
                               false,                           // is_const
                               nullptr,                         // constructor
                               ast::VariableDecorationList{});  // decorations
-    body->append(create<ast::VariableDeclStatement>(Source{}, call_result));
+    stmts.emplace_back(
+        create<ast::VariableDeclStatement>(Source{}, call_result));
 
     ast::ExpressionList call_params;
     call_params.push_back(create<ast::IdentifierExpression>(
@@ -729,14 +739,15 @@
             "textureSampleCompare"),
         call_params);
 
-    body->append(create<ast::AssignmentStatement>(
+    stmts.emplace_back(create<ast::AssignmentStatement>(
         Source{},
         create<ast::IdentifierExpression>(
             Source{}, mod()->RegisterSymbol("sampler_result"),
             "sampler_result"),
         call_expr));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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(), void_type(),
                                  body, decorations);
@@ -1557,20 +1568,21 @@
   AddReferenceFunc("ub_bar_func", "ub_bar");
   AddReferenceFunc("ub_baz_func", "ub_baz");
 
-  auto AddFuncCall = [&](ast::BlockStatement* body, const std::string& callee) {
+  auto FuncCall = [&](const std::string& callee) {
     auto* ident_expr = create<ast::IdentifierExpression>(
         Source{}, mod()->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    body->append(create<ast::CallStatement>(Source{}, call_expr));
+    return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(Source{});
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    FuncCall("ub_foo_func"),
+                    FuncCall("ub_bar_func"),
+                    FuncCall("ub_baz_func"),
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
-  AddFuncCall(body, "ub_foo_func");
-  AddFuncCall(body, "ub_bar_func");
-  AddFuncCall(body, "ub_baz_func");
-
-  body->append(create<ast::ReturnStatement>(Source{}));
   ast::Function* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("ep_func"), "ep_func",
       ast::VariableList(), void_type(), body,
@@ -1705,20 +1717,21 @@
   AddReferenceFunc("sb_bar_func", "sb_bar");
   AddReferenceFunc("sb_baz_func", "sb_baz");
 
-  auto AddFuncCall = [&](ast::BlockStatement* body, const std::string& callee) {
+  auto FuncCall = [&](const std::string& callee) {
     auto* ident_expr = create<ast::IdentifierExpression>(
         Source{}, mod()->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    body->append(create<ast::CallStatement>(Source{}, call_expr));
+    return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(Source{});
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    FuncCall("sb_foo_func"),
+                    FuncCall("sb_bar_func"),
+                    FuncCall("sb_baz_func"),
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
-  AddFuncCall(body, "sb_foo_func");
-  AddFuncCall(body, "sb_bar_func");
-  AddFuncCall(body, "sb_baz_func");
-
-  body->append(create<ast::ReturnStatement>(Source{}));
   ast::Function* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("ep_func"), "ep_func",
       ast::VariableList(), void_type(), body,
@@ -1880,20 +1893,21 @@
   AddReferenceFunc("sb_bar_func", "sb_bar");
   AddReferenceFunc("sb_baz_func", "sb_baz");
 
-  auto AddFuncCall = [&](ast::BlockStatement* body, const std::string& callee) {
+  auto FuncCall = [&](const std::string& callee) {
     auto* ident_expr = create<ast::IdentifierExpression>(
         Source{}, mod()->RegisterSymbol(callee), callee);
     auto* call_expr = create<ast::CallExpression>(Source{}, ident_expr,
                                                   ast::ExpressionList());
-    body->append(create<ast::CallStatement>(Source{}, call_expr));
+    return create<ast::CallStatement>(Source{}, call_expr);
   };
-  auto* body = create<ast::BlockStatement>(Source{});
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    FuncCall("sb_foo_func"),
+                    FuncCall("sb_bar_func"),
+                    FuncCall("sb_baz_func"),
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
-  AddFuncCall(body, "sb_foo_func");
-  AddFuncCall(body, "sb_bar_func");
-  AddFuncCall(body, "sb_baz_func");
-
-  body->append(create<ast::ReturnStatement>(Source{}));
   ast::Function* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("ep_func"), "ep_func",
       ast::VariableList(), void_type(), body,
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 29907df..386fdf1 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -608,7 +608,7 @@
   std::unordered_set<uint32_t> visited_;
 };
 
-/// A StatementBuilder for ast::SwitchStatment
+/// A StatementBuilder for ast::SwitchStatement
 /// @see StatementBuilder
 struct SwitchStatementBuilder
     : public Castable<SwitchStatementBuilder, StatementBuilder> {
@@ -730,32 +730,17 @@
       completion_action_(completion_action),
       cases_(cases) {}
 
-FunctionEmitter::StatementBlock::StatementBlock(StatementBlock&& other)
-    : construct_(other.construct_),
-      end_id_(other.end_id_),
-      completion_action_(std::move(other.completion_action_)),
-      statements_(std::move(other.statements_)),
-      cases_(std::move(other.cases_)) {
-  other.statements_.clear();
-}
+FunctionEmitter::StatementBlock::StatementBlock(StatementBlock&& other) =
+    default;
 
-FunctionEmitter::StatementBlock::~StatementBlock() {
-  if (!finalized_) {
-    // Delete builders that have not been built with Finalize()
-    for (auto* statement : statements_) {
-      if (auto* builder = statement->As<StatementBuilder>()) {
-        delete builder;
-      }
-    }
-  }
-}
+FunctionEmitter::StatementBlock::~StatementBlock() = default;
 
 void FunctionEmitter::StatementBlock::Finalize(ast::Module* mod) {
   assert(!finalized_ /* Finalize() must only be called once */);
+
   for (size_t i = 0; i < statements_.size(); i++) {
     if (auto* builder = statements_[i]->As<StatementBuilder>()) {
       statements_[i] = builder->Build(mod);
-      delete builder;
     }
   }
 
@@ -820,12 +805,10 @@
 
 ast::Statement* FunctionEmitter::AddStatement(ast::Statement* statement) {
   assert(!statements_stack_.empty());
-  auto* result = statement;
-  if (result != nullptr) {
-    auto& block = statements_stack_.back();
-    block.Add(statement);
+  if (statement != nullptr) {
+    statements_stack_.back().Add(statement);
   }
-  return result;
+  return statement;
 }
 
 ast::Statement* FunctionEmitter::LastStatement() {
diff --git a/src/reader/spirv/function.h b/src/reader/spirv/function.h
index e1f0968..533c7eb 100644
--- a/src/reader/spirv/function.h
+++ b/src/reader/spirv/function.h
@@ -834,12 +834,15 @@
   /// @returns a pointer to the statement.
   ast::Statement* AddStatement(ast::Statement* statement);
 
+  /// AddStatementBuilder() constructs and adds the StatementBuilder of type
+  /// `T` to the top of the statement stack.
+  /// @param args the arguments forwarded to the T constructor
+  /// @return the built StatementBuilder
   template <typename T, typename... ARGS>
   T* AddStatementBuilder(ARGS&&... args) {
-    // The builder is temporary and is not owned by the module.
-    auto builder = new T(std::forward<ARGS>(args)...);
-    AddStatement(builder);
-    return builder;
+    assert(!statements_stack_.empty());
+    return statements_stack_.back().AddStatementBuilder<T>(
+        std::forward<ARGS>(args)...);
   }
 
   /// Returns the source record for the given instruction.
@@ -876,6 +879,20 @@
     /// Add() must not be called after calling Finalize().
     void Add(ast::Statement* statement);
 
+    /// AddStatementBuilder() constructs and adds the StatementBuilder of type
+    /// `T` to the block.
+    /// Add() must not be called after calling Finalize().
+    /// @param args the arguments forwarded to the T constructor
+    /// @return the built StatementBuilder
+    template <typename T, typename... ARGS>
+    T* AddStatementBuilder(ARGS&&... args) {
+      auto builder = std::make_unique<T>(std::forward<ARGS>(args)...);
+      auto* ptr = builder.get();
+      Add(ptr);
+      builders_.emplace_back(std::move(builder));
+      return ptr;
+    }
+
     /// @param construct the construct which this construct constributes to
     void SetConstruct(const Construct* construct) { construct_ = construct; }
 
@@ -883,7 +900,7 @@
     const Construct* Construct() const { return construct_; }
 
     /// @return the ID of the block at which the completion action should be
-    /// triggerd and this statement block discarded. This is often the `end_id`
+    /// triggered and this statement block discarded. This is often the `end_id`
     /// of `construct` itself.
     uint32_t EndId() const { return end_id_; }
 
@@ -901,7 +918,7 @@
    private:
     /// The construct to which this construct constributes.
     const spirv::Construct* construct_;
-    /// The ID of the block at which the completion action should be triggerd
+    /// The ID of the block at which the completion action should be triggered
     /// and this statement block discarded. This is often the `end_id` of
     /// `construct` itself.
     uint32_t const end_id_;
@@ -914,6 +931,9 @@
     ast::StatementList statements_;
     /// The list of switch cases being built, if this construct is a switch.
     ast::CaseStatementList* cases_ = nullptr;
+
+    /// Owned statement builders
+    std::vector<std::unique_ptr<StatementBuilder>> builders_;
     /// True if Finalize() has been called.
     bool finalized_ = false;
   };
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 637ab83..6219b32 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1439,14 +1439,14 @@
 //   : statement*
 Expect<ast::BlockStatement*> ParserImpl::expect_statements() {
   bool errored = false;
-  auto* ret = create<ast::BlockStatement>(Source{});
+  ast::StatementList stmts;
 
   while (synchronized_) {
     auto stmt = statement();
     if (stmt.errored) {
       errored = true;
     } else if (stmt.matched) {
-      ret->append(stmt.value);
+      stmts.emplace_back(stmt.value);
     } else {
       break;
     }
@@ -1455,7 +1455,7 @@
   if (errored)
     return Failure::kErrored;
 
-  return ret;
+  return create<ast::BlockStatement>(Source{}, stmts);
 }
 
 // statement
@@ -1828,14 +1828,14 @@
 //   | statement case_body
 //   | FALLTHROUGH SEMICOLON
 Maybe<ast::BlockStatement*> ParserImpl::case_body() {
-  auto* ret = create<ast::BlockStatement>(Source{});
+  ast::StatementList stmts;
   for (;;) {
     Source source;
     if (match(Token::Type::kFallthrough, &source)) {
       if (!expect("fallthrough statement", Token::Type::kSemicolon))
         return Failure::kErrored;
 
-      ret->append(create<ast::FallthroughStatement>(source));
+      stmts.emplace_back(create<ast::FallthroughStatement>(source));
       break;
     }
 
@@ -1845,10 +1845,10 @@
     if (!stmt.matched)
       break;
 
-    ret->append(stmt.value);
+    stmts.emplace_back(stmt.value);
   }
 
-  return ret;
+  return create<ast::BlockStatement>(Source{}, stmts);
 }
 
 // loop_stmt
@@ -1972,8 +1972,10 @@
         header->condition->source(), ast::UnaryOp::kNot, header->condition);
     // { break; }
     auto* break_stmt = create<ast::BreakStatement>(not_condition->source());
-    auto* break_body = create<ast::BlockStatement>(not_condition->source());
-    break_body->append(break_stmt);
+    auto* break_body =
+        create<ast::BlockStatement>(not_condition->source(), ast::StatementList{
+                                                                 break_stmt,
+                                                             });
     // if (!condition) { break; }
     auto* break_if_not_condition =
         create<ast::IfStatement>(not_condition->source(), not_condition,
@@ -1983,17 +1985,19 @@
 
   ast::BlockStatement* continuing_body = nullptr;
   if (header->continuing != nullptr) {
-    continuing_body = create<ast::BlockStatement>(header->continuing->source());
-    continuing_body->append(header->continuing);
+    continuing_body = create<ast::BlockStatement>(header->continuing->source(),
+                                                  ast::StatementList{
+                                                      header->continuing,
+                                                  });
   }
 
   auto* loop = create<ast::LoopStatement>(source, body.value, continuing_body);
 
   if (header->initializer != nullptr) {
-    auto* result = create<ast::BlockStatement>(source);
-    result->append(header->initializer);
-    result->append(loop);
-    return result;
+    return create<ast::BlockStatement>(source, ast::StatementList{
+                                                   header->initializer,
+                                                   loop,
+                                               });
   }
 
   return loop;
@@ -2059,7 +2063,7 @@
 //   : CONTINUING body_stmt
 Maybe<ast::BlockStatement*> ParserImpl::continuing_stmt() {
   if (!match(Token::Type::kContinuing))
-    return create<ast::BlockStatement>(Source{});
+    return create<ast::BlockStatement>(Source{}, ast::StatementList{});
 
   return expect_body_stmt();
 }
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index 2f878d0..1f152f2 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -91,24 +91,21 @@
 };
 
 struct ModuleBuilder : public ast::BuilderWithModule {
-  ModuleBuilder() : body_(create<ast::BlockStatement>(Source{})) {
-    mod->AddFunction(create<ast::Function>(
-        Source{}, mod->RegisterSymbol("func"), "func", ast::VariableList{},
-        ty.void_, body_, ast::FunctionDecorationList{}));
-  }
-
   ast::Module Module() {
     Build();
+    auto* body = create<ast::BlockStatement>(Source{}, statements);
+    mod->AddFunction(create<ast::Function>(
+        Source{}, mod->RegisterSymbol("func"), "func", ast::VariableList{},
+        ty.void_, body, ast::FunctionDecorationList{}));
     return std::move(*mod);
   }
 
  protected:
   virtual void Build() = 0;
   void OnVariableBuilt(ast::Variable* var) override {
-    ASSERT_NE(body_, nullptr);
-    body_->append(create<ast::VariableDeclStatement>(Source{}, var));
+    statements.emplace_back(create<ast::VariableDeclStatement>(Source{}, var));
   }
-  ast::BlockStatement* body_ = nullptr;
+  ast::StatementList statements;
 };
 
 TEST_F(BoundArrayAccessorsTest, Ptrs_Clamp) {
diff --git a/src/transform/emit_vertex_point_size_test.cc b/src/transform/emit_vertex_point_size_test.cc
index d6f5627..a089d3e 100644
--- a/src/transform/emit_vertex_point_size_test.cc
+++ b/src/transform/emit_vertex_point_size_test.cc
@@ -53,16 +53,18 @@
 TEST_F(EmitVertexPointSizeTest, VertexStageBasic) {
   struct Builder : ModuleBuilder {
     void Build() override {
-      auto* block = create<ast::BlockStatement>(Source{});
-
-      block->append(create<ast::VariableDeclStatement>(
-          Source{}, Var("builtin_assignments_should_happen_before_this",
-                        tint::ast::StorageClass::kFunction, ty.f32)));
+      auto* block = create<ast::BlockStatement>(
+          Source{},
+          ast::StatementList{
+              create<ast::VariableDeclStatement>(
+                  Source{}, Var("builtin_assignments_should_happen_before_this",
+                                tint::ast::StorageClass::kFunction, ty.f32)),
+          });
 
       auto a_sym = mod->RegisterSymbol("non_entry_a");
       mod->AddFunction(create<ast::Function>(
           Source{}, a_sym, "non_entry_a", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{}));
 
       auto entry_sym = mod->RegisterSymbol("entry");
@@ -77,7 +79,7 @@
       auto b_sym = mod->RegisterSymbol("non_entry_b");
       mod->AddFunction(create<ast::Function>(
           Source{}, b_sym, "non_entry_b", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{}));
     }
   };
@@ -131,13 +133,13 @@
       auto a_sym = mod->RegisterSymbol("non_entry_a");
       mod->AddFunction(create<ast::Function>(
           Source{}, a_sym, "non_entry_a", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{}));
 
       auto entry_sym = mod->RegisterSymbol("entry");
       mod->AddFunction(create<ast::Function>(
           Source{}, entry_sym, "entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{
               create<ast::StageDecoration>(ast::PipelineStage::kVertex,
                                            Source{}),
@@ -146,7 +148,7 @@
       auto b_sym = mod->RegisterSymbol("non_entry_b");
       mod->AddFunction(create<ast::Function>(
           Source{}, b_sym, "non_entry_b", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{}));
     }
   };
@@ -193,7 +195,7 @@
       auto frag_sym = mod->RegisterSymbol("fragment_entry");
       auto* fragment_entry = create<ast::Function>(
           Source{}, frag_sym, "fragment_entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{
               create<ast::StageDecoration>(ast::PipelineStage::kFragment,
                                            Source{}),
@@ -203,7 +205,7 @@
       auto comp_sym = mod->RegisterSymbol("compute_entry");
       auto* compute_entry = create<ast::Function>(
           Source{}, comp_sym, "compute_entry", ast::VariableList{}, ty.void_,
-          create<ast::BlockStatement>(Source{}),
+          create<ast::BlockStatement>(Source{}, ast::StatementList{}),
           ast::FunctionDecorationList{
               create<ast::StageDecoration>(ast::PipelineStage::kCompute,
                                            Source{}),
diff --git a/src/transform/first_index_offset.cc b/src/transform/first_index_offset.cc
index 5168e65..97c7670 100644
--- a/src/transform/first_index_offset.cc
+++ b/src/transform/first_index_offset.cc
@@ -154,24 +154,25 @@
         if (buffer_var == nullptr) {
           return nullptr;  // no transform need, just clone func
         }
-        auto* body = ctx.mod->create<ast::BlockStatement>(
-            ctx.Clone(func->body()->source()));
+        ast::StatementList statements;
         for (const auto& data : func->local_referenced_builtin_variables()) {
           if (data.second->value() == ast::Builtin::kVertexIdx) {
-            body->append(CreateFirstIndexOffset(
+            statements.emplace_back(CreateFirstIndexOffset(
                 vertex_index_name, kFirstVertexName, buffer_var, ctx.mod));
           } else if (data.second->value() == ast::Builtin::kInstanceIdx) {
-            body->append(CreateFirstIndexOffset(
+            statements.emplace_back(CreateFirstIndexOffset(
                 instance_index_name, kFirstInstanceName, buffer_var, ctx.mod));
           }
         }
         for (auto* s : *func->body()) {
-          body->append(ctx.Clone(s));
+          statements.emplace_back(ctx.Clone(s));
         }
         return ctx.mod->create<ast::Function>(
             ctx.Clone(func->source()), func->symbol(), func->name(),
             ctx.Clone(func->params()), ctx.Clone(func->return_type()),
-            ctx.Clone(body), ctx.Clone(func->decorations()));
+            ctx.mod->create<ast::BlockStatement>(
+                ctx.Clone(func->body()->source()), statements),
+            ctx.Clone(func->decorations()));
       });
 
   in->Clone(&ctx);
diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc
index 88196b3..2e8164a 100644
--- a/src/transform/first_index_offset_test.cc
+++ b/src/transform/first_index_offset_test.cc
@@ -58,10 +58,11 @@
   }
 
   ast::Function* AddFunction(const std::string& name,
-                             ast::VariableList params = {}) {
+                             ast::StatementList stmts) {
     auto* func = create<ast::Function>(
-        Source{}, mod->RegisterSymbol(name), name, std::move(params), ty.u32,
-        create<ast::BlockStatement>(Source{}), ast::FunctionDecorationList());
+        Source{}, mod->RegisterSymbol(name), name, ast::VariableList{}, ty.u32,
+        create<ast::BlockStatement>(Source{}, stmts),
+        ast::FunctionDecorationList{});
     mod->AddFunction(func);
     return func;
   }
@@ -73,10 +74,14 @@
   struct Builder : public ModuleBuilder {
     void Build() override {
       AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx);
-      AddFunction("test")->body()->append(create<ast::ReturnStatement>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")));
+      AddFunction(
+          "test",
+          {
+              create<ast::ReturnStatement>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")),
+          });
     }
   };
 
@@ -116,10 +121,14 @@
   struct Builder : public ModuleBuilder {
     void Build() override {
       AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx);
-      AddFunction("test")->body()->append(create<ast::ReturnStatement>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")));
+      AddFunction(
+          "test",
+          {
+              create<ast::ReturnStatement>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")),
+          });
     }
   };
 
@@ -194,10 +203,14 @@
   struct Builder : public ModuleBuilder {
     void Build() override {
       AddBuiltinInput("inst_idx", ast::Builtin::kInstanceIdx);
-      AddFunction("test")->body()->append(create<ast::ReturnStatement>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod->RegisterSymbol("inst_idx"), "inst_idx")));
+      AddFunction(
+          "test",
+          {
+              create<ast::ReturnStatement>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod->RegisterSymbol("inst_idx"), "inst_idx")),
+          });
     }
   };
 
@@ -272,8 +285,9 @@
     void Build() override {
       AddBuiltinInput("inst_idx", ast::Builtin::kInstanceIdx);
       AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx);
-      AddFunction("test")->body()->append(
-          create<ast::ReturnStatement>(Source{}, Expr(1u)));
+      AddFunction("test", {
+                              create<ast::ReturnStatement>(Source{}, Expr(1u)),
+                          });
     }
   };
 
@@ -348,18 +362,25 @@
   struct Builder : public ModuleBuilder {
     void Build() override {
       AddBuiltinInput("vert_idx", ast::Builtin::kVertexIdx);
-      ast::Function* func1 = AddFunction("func1");
-      func1->body()->append(create<ast::ReturnStatement>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")));
-      ast::Function* func2 = AddFunction("func2");
-      func2->body()->append(create<ast::ReturnStatement>(
-          Source{}, create<ast::CallExpression>(
-                        Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("func1"), "func1"),
-                        ast::ExpressionList{})));
+      AddFunction(
+          "func1",
+          {
+              create<ast::ReturnStatement>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod->RegisterSymbol("vert_idx"), "vert_idx")),
+          });
+      AddFunction(
+          "func2",
+          {
+              create<ast::ReturnStatement>(
+                  Source{},
+                  create<ast::CallExpression>(
+                      Source{},
+                      create<ast::IdentifierExpression>(
+                          Source{}, mod->RegisterSymbol("func1"), "func1"),
+                      ast::ExpressionList{})),
+          });
     }
   };
 
diff --git a/src/transform/vertex_pulling.cc b/src/transform/vertex_pulling.cc
index 23b9763..163d875 100644
--- a/src/transform/vertex_pulling.cc
+++ b/src/transform/vertex_pulling.cc
@@ -105,7 +105,7 @@
   state.FindOrInsertInstanceIndexIfUsed();
   state.ConvertVertexInputVariablesToPrivate();
   state.AddVertexStorageBuffers();
-  state.AddVertexPullingPreamble(func);
+  func->body()->insert(0, state.CreateVertexPullingPreamble());
 
   return out;
 }
@@ -286,13 +286,11 @@
   mod->AddConstructedType(struct_type);
 }
 
-void VertexPulling::State::AddVertexPullingPreamble(
-    ast::Function* vertex_func) {
+ast::BlockStatement* VertexPulling::State::CreateVertexPullingPreamble() {
   // Assign by looking at the vertex descriptor to find attributes with matching
   // location.
 
-  // A block statement allowing us to use append instead of insert
-  auto* block = mod->create<ast::BlockStatement>(Source{});
+  ast::StatementList stmts;
 
   // Declare the |kPullingPosVarName| variable in the shader
   auto* pos_declaration = mod->create<ast::VariableDeclStatement>(
@@ -308,7 +306,7 @@
   // |kPullingPosVarName| refers to the byte location of the current read. We
   // declare a variable in the shader to avoid having to reuse Expression
   // objects.
-  block->append(pos_declaration);
+  stmts.emplace_back(pos_declaration);
 
   for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
     const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[i];
@@ -339,9 +337,9 @@
       // Update position of the read
       auto* set_pos_expr = mod->create<ast::AssignmentStatement>(
           Source{}, CreatePullingPositionIdent(), pos_value);
-      block->append(set_pos_expr);
+      stmts.emplace_back(set_pos_expr);
 
-      block->append(mod->create<ast::AssignmentStatement>(
+      stmts.emplace_back(mod->create<ast::AssignmentStatement>(
           Source{},
           mod->create<ast::IdentifierExpression>(
               Source{}, mod->RegisterSymbol(v->name()), v->name()),
@@ -349,7 +347,7 @@
     }
   }
 
-  vertex_func->body()->insert(0, block);
+  return mod->create<ast::BlockStatement>(Source{}, stmts);
 }
 
 ast::Expression* VertexPulling::State::GenUint(uint32_t value) {
diff --git a/src/transform/vertex_pulling.h b/src/transform/vertex_pulling.h
index be3f9ca..4f55b1f 100644
--- a/src/transform/vertex_pulling.h
+++ b/src/transform/vertex_pulling.h
@@ -197,8 +197,8 @@
     /// Adds storage buffer decorated variables for the vertex buffers
     void AddVertexStorageBuffers();
 
-    /// Adds assignment to the variables from the buffers
-    void AddVertexPullingPreamble(ast::Function* vertex_func);
+    /// Creates and returns the assignment to the variables from the buffers
+    ast::BlockStatement* CreateVertexPullingPreamble();
 
     /// Generates an expression holding a constant uint
     /// @param value uint value
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index b066e16..30145ce 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -47,8 +47,9 @@
   // Create basic module with an entry point and vertex function
   void InitBasicModule() {
     auto* func = create<ast::Function>(
-        Source{}, mod_->RegisterSymbol("main"), "main", ast::VariableList{},
-        mod_->create<ast::type::Void>(), create<ast::BlockStatement>(Source{}),
+        Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{},
+        mod_->create<ast::type::Void>(),
+        create<ast::BlockStatement>(Source{}, ast::StatementList{}),
         ast::FunctionDecorationList{create<ast::StageDecoration>(
             ast::PipelineStage::kVertex, Source{})});
     mod()->AddFunction(func);
@@ -135,7 +136,8 @@
 TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("main"), "main", ast::VariableList{},
-      mod()->create<ast::type::Void>(), create<ast::BlockStatement>(Source{}),
+      mod()->create<ast::type::Void>(),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index db04d8f..36eb700 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -151,9 +151,10 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 3));
   ast::CaseStatement cse(Source{}, lit, body);
@@ -174,8 +175,10 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  ast::BlockStatement block(Source{});
-  block.append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
+  ast::BlockStatement block(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineResultType(&block));
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -193,9 +196,10 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   ast::ElseStatement stmt(
       Source{},
       create<ast::ScalarConstructorExpression>(
@@ -220,9 +224,11 @@
   auto* else_rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(
-      create<ast::AssignmentStatement>(Source{}, else_lhs, else_rhs));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{},
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Source{}, else_lhs, else_rhs),
+      });
 
   auto* else_stmt = create<ast::ElseStatement>(
       Source{},
@@ -235,9 +241,10 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   ast::IfStatement stmt(
       Source{},
       create<ast::ScalarConstructorExpression>(
@@ -266,18 +273,21 @@
   auto* body_rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(Source{}, body_lhs, body_rhs));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{},
+      ast::StatementList{
+          create<ast::AssignmentStatement>(Source{}, body_lhs, body_rhs),
+      });
   auto* continuing_lhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
   auto* continuing_rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(Source{}, continuing_lhs,
-                                                      continuing_rhs));
-
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, continuing_lhs,
+                                                     continuing_rhs),
+                });
   ast::LoopStatement stmt(Source{}, body, continuing);
 
   EXPECT_TRUE(td()->DetermineResultType(&stmt));
@@ -319,9 +329,10 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 3));
 
@@ -350,7 +361,8 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{}, mod->RegisterSymbol("my_func"), "my_func", params, &f32,
-      create<ast::BlockStatement>(Source{}), ast::FunctionDecorationList{});
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -380,16 +392,21 @@
                                         mod->RegisterSymbol("func"), "func"),
       call_params);
   ast::VariableList params0;
-  auto* main_body = create<ast::BlockStatement>(Source{});
-  main_body->append(create<ast::CallStatement>(Source{}, call_expr));
-  main_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* main_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::CallStatement>(Source{}, call_expr),
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   auto* func_main = create<ast::Function>(Source{}, mod->RegisterSymbol("main"),
                                           "main", params0, &f32, main_body,
                                           ast::FunctionDecorationList{});
   mod->AddFunction(func_main);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func =
       create<ast::Function>(Source{}, mod->RegisterSymbol("func"), "func",
                             params0, &f32, body, ast::FunctionDecorationList{});
@@ -675,7 +692,8 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{}, mod->RegisterSymbol("my_func"), "my_func", params, &f32,
-      create<ast::BlockStatement>(Source{}), ast::FunctionDecorationList{});
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -698,7 +716,8 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{}, mod->RegisterSymbol("my_func"), "my_func", params, &f32,
-      create<ast::BlockStatement>(Source{}), ast::FunctionDecorationList{});
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -851,13 +870,14 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::AssignmentStatement>(
-      Source{}, my_var,
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_var"),
-                                        "my_var")));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::AssignmentStatement>(
+                        Source{}, my_var,
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_var"), "my_var")),
+                });
   ast::Function f(Source{}, mod->RegisterSymbol("my_func"), "my_func", {}, &f32,
                   body, ast::FunctionDecorationList{});
 
@@ -873,21 +893,23 @@
   auto* my_var = create<ast::IdentifierExpression>(
       Source{}, mod->RegisterSymbol("my_var"), "my_var");
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "my_var",                          // name
-                            ast::StorageClass::kNone,          // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
-
-  body->append(create<ast::AssignmentStatement>(
-      Source{}, my_var,
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_var"),
-                                        "my_var")));
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                         // source
+                            "my_var",                         // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{})),  // decorations
+          create<ast::AssignmentStatement>(
+              Source{}, my_var,
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("my_var"), "my_var")),
+      });
 
   ast::Function f(Source{}, mod->RegisterSymbol("myfunc"), "my_func", {}, &f32,
                   body, ast::FunctionDecorationList{});
@@ -909,21 +931,23 @@
   auto* my_var = create<ast::IdentifierExpression>(
       Source{}, mod->RegisterSymbol("my_var"), "my_var");
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "my_var",                          // name
-                            ast::StorageClass::kNone,          // storage_class
-                            &ptr,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
-
-  body->append(create<ast::AssignmentStatement>(
-      Source{}, my_var,
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_var"),
-                                        "my_var")));
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                         // source
+                            "my_var",                         // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &ptr,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{})),  // decorations
+          create<ast::AssignmentStatement>(
+              Source{}, my_var,
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("my_var"), "my_var")),
+      });
 
   ast::Function f(Source{}, mod->RegisterSymbol("my_func"), "my_func", {}, &f32,
                   body, ast::FunctionDecorationList{});
@@ -944,7 +968,8 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{}, mod->RegisterSymbol("my_func"), "my_func", params, &f32,
-      create<ast::BlockStatement>(Source{}), ast::FunctionDecorationList{});
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod->AddFunction(func);
 
   // Register the function
@@ -1013,31 +1038,34 @@
   mod->AddGlobalVariable(priv_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("out_var"), "out_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("in_var"),
-                                        "in_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("wg_var"),
-                                        "wg_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("wg_var"),
-                                        "wg_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("sb_var"),
-                                        "sb_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("sb_var"),
-                                        "sb_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("priv_var"), "priv_var"),
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("priv_var"), "priv_var")));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("out_var"), "out_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("in_var"), "in_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("wg_var"), "wg_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("wg_var"), "wg_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("sb_var"), "sb_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("sb_var"), "sb_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("priv_var"), "priv_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("priv_var"), "priv_var")),
+      });
   auto* func =
       create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"), "my_func",
                             params, &f32, body, ast::FunctionDecorationList{});
@@ -1106,31 +1134,34 @@
   mod->AddGlobalVariable(wg_var);
   mod->AddGlobalVariable(priv_var);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("out_var"), "out_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("in_var"),
-                                        "in_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("wg_var"),
-                                        "wg_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("wg_var"),
-                                        "wg_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("sb_var"),
-                                        "sb_var"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("sb_var"),
-                                        "sb_var")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("priv_var"), "priv_var"),
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("priv_var"), "priv_var")));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("out_var"), "out_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("in_var"), "in_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("wg_var"), "wg_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("wg_var"), "wg_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("sb_var"), "sb_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("sb_var"), "sb_var")),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("priv_var"), "priv_var"),
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("priv_var"), "priv_var")),
+      });
   ast::VariableList params;
   auto* func =
       create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"), "my_func",
@@ -1138,16 +1169,20 @@
 
   mod->AddFunction(func);
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(
-          Source{}, mod->RegisterSymbol("out_var"), "out_var"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod->RegisterSymbol("my_func"), "my_func"),
-          ast::ExpressionList{})));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("out_var"), "out_var"),
+              create<ast::CallExpression>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod->RegisterSymbol("my_func"), "my_func"),
+                  ast::ExpressionList{})),
+      });
+
   auto* func2 =
       create<ast::Function>(Source{}, mod->RegisterSymbol("func"), "func",
                             params, &f32, body, ast::FunctionDecorationList{});
@@ -1178,15 +1213,17 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("var"),
-                                        "var"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.f))));
-
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("var"), "var"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.f))),
+      });
   ast::VariableList params;
   auto* func =
       create<ast::Function>(Source{}, mod->RegisterSymbol("my_func"), "my_func",
@@ -2869,8 +2906,9 @@
                             ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(Source{}, var);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(stmt);
+  auto* body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                         stmt,
+                                                     });
   auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("func"),
                                      "func", ast::VariableList{}, &i32, body,
                                      ast::FunctionDecorationList{});
@@ -2894,8 +2932,9 @@
                             ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(Source{}, var);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(stmt);
+  auto* body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                         stmt,
+                                                     });
   auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("func"),
                                      "func", ast::VariableList{}, &i32, body,
                                      ast::FunctionDecorationList{});
@@ -2919,8 +2958,9 @@
                             ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(Source{}, var);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(stmt);
+  auto* body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                         stmt,
+                                                     });
   auto* func = create<ast::Function>(Source{}, mod->RegisterSymbol("func"),
                                      "func", ast::VariableList{}, &i32, body,
                                      ast::FunctionDecorationList{});
@@ -5237,69 +5277,82 @@
   // ep_2 -> {}
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
+  auto* body = create<ast::BlockStatement>(Source{}, ast::StatementList{});
   auto* func_b =
       create<ast::Function>(Source{}, mod->RegisterSymbol("b"), "b", params,
                             &f32, body, ast::FunctionDecorationList{});
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("second"),
-                                        "second"),
-      create<ast::CallExpression>(Source{},
-                                  create<ast::IdentifierExpression>(
-                                      Source{}, mod->RegisterSymbol("b"), "b"),
-                                  ast::ExpressionList{})));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("second"), "second"),
+                        create<ast::CallExpression>(
+                            Source{},
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("b"), "b"),
+                            ast::ExpressionList{})),
+                });
   auto* func_c =
       create<ast::Function>(Source{}, mod->RegisterSymbol("c"), "c", params,
                             &f32, body, ast::FunctionDecorationList{});
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("first"),
-                                        "first"),
-      create<ast::CallExpression>(Source{},
-                                  create<ast::IdentifierExpression>(
-                                      Source{}, mod->RegisterSymbol("c"), "c"),
-                                  ast::ExpressionList{})));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("first"), "first"),
+                        create<ast::CallExpression>(
+                            Source{},
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("c"), "c"),
+                            ast::ExpressionList{})),
+                });
   auto* func_a =
       create<ast::Function>(Source{}, mod->RegisterSymbol("a"), "a", params,
                             &f32, body, ast::FunctionDecorationList{});
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("call_a"),
-                                        "call_a"),
-      create<ast::CallExpression>(Source{},
-                                  create<ast::IdentifierExpression>(
-                                      Source{}, mod->RegisterSymbol("a"), "a"),
-                                  ast::ExpressionList{})));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("call_b"),
-                                        "call_b"),
-      create<ast::CallExpression>(Source{},
-                                  create<ast::IdentifierExpression>(
-                                      Source{}, mod->RegisterSymbol("b"), "b"),
-                                  ast::ExpressionList{})));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("call_a"), "call_a"),
+                        create<ast::CallExpression>(
+                            Source{},
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("a"), "a"),
+                            ast::ExpressionList{})),
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("call_b"), "call_b"),
+                        create<ast::CallExpression>(
+                            Source{},
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("b"), "b"),
+                            ast::ExpressionList{})),
+                });
   auto* ep_1 = create<ast::Function>(
       Source{}, mod->RegisterSymbol("ep_1"), "ep_1", params, &f32, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}),
       });
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("call_c"),
-                                        "call_c"),
-      create<ast::CallExpression>(Source{},
-                                  create<ast::IdentifierExpression>(
-                                      Source{}, mod->RegisterSymbol("c"), "c"),
-                                  ast::ExpressionList{})));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("call_c"), "call_c"),
+                        create<ast::CallExpression>(
+                            Source{},
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("c"), "c"),
+                            ast::ExpressionList{})),
+                });
   auto* ep_2 = create<ast::Function>(
       Source{}, mod->RegisterSymbol("ep_2"), "ep_2", params, &f32, body,
       ast::FunctionDecorationList{
diff --git a/src/validator/validator_control_block_test.cc b/src/validator/validator_control_block_test.cc
index 55a44ac..0cbd07b 100644
--- a/src/validator/validator_control_block_test.cc
+++ b/src/validator/validator_control_block_test.cc
@@ -57,14 +57,17 @@
   auto* cond = create<ast::IdentifierExpression>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a");
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   ast::CaseStatementList body;
   body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, body));
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, body),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -96,12 +99,15 @@
   csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(
-      Source{}, csl, create<ast::BlockStatement>(Source{})));
+      Source{}, csl,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{Source::Location{12, 34}},
-                                             cond, body));
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(
+                        Source{Source::Location{12, 34}}, cond, body),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -134,25 +140,30 @@
       Source{}, mod()->RegisterSymbol("a"), "a");
 
   ast::CaseSelectorList default_csl_1;
-  auto* block_default_1 = create<ast::BlockStatement>(Source{});
+  auto* block_default_1 =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl_1, block_default_1));
 
   ast::CaseSelectorList csl_case_1;
   csl_case_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
-  auto* block_case_1 = create<ast::BlockStatement>(Source{});
+  auto* block_case_1 =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, csl_case_1, block_case_1));
 
   ast::CaseSelectorList default_csl_2;
-  auto* block_default_2 = create<ast::BlockStatement>(Source{});
+  auto* block_default_2 =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl_2, block_default_2));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{Source::Location{12, 34}},
-                                             cond, switch_body));
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(
+                        Source{Source::Location{12, 34}}, cond, switch_body),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
@@ -187,19 +198,21 @@
 
   ast::CaseSelectorList csl;
   csl.push_back(create<ast::UintLiteral>(Source{}, &u32, 1));
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{Source::Location{12, 34}}, csl,
-                                 create<ast::BlockStatement>(Source{})));
+  switch_body.push_back(create<ast::CaseStatement>(
+      Source{Source::Location{12, 34}}, csl,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, switch_body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -233,19 +246,21 @@
 
   ast::CaseSelectorList csl;
   csl.push_back(create<ast::SintLiteral>(Source{}, &i32, -1));
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{Source::Location{12, 34}}, csl,
-                                 create<ast::BlockStatement>(Source{})));
+  switch_body.push_back(create<ast::CaseStatement>(
+      Source{Source::Location{12, 34}}, csl,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, switch_body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -279,24 +294,27 @@
   ast::CaseSelectorList csl_1;
   csl_1.push_back(create<ast::UintLiteral>(Source{}, &u32, 0));
   switch_body.push_back(create<ast::CaseStatement>(
-      Source{}, csl_1, create<ast::BlockStatement>(Source{})));
+      Source{}, csl_1,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList csl_2;
   csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2));
   csl_2.push_back(create<ast::UintLiteral>(Source{}, &u32, 2));
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{Source::Location{12, 34}}, csl_2,
-                                 create<ast::BlockStatement>(Source{})));
+  switch_body.push_back(create<ast::CaseStatement>(
+      Source{Source::Location{12, 34}}, csl_2,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, switch_body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -330,26 +348,29 @@
   ast::CaseSelectorList csl_1;
   csl_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 10));
   switch_body.push_back(create<ast::CaseStatement>(
-      Source{}, csl_1, create<ast::BlockStatement>(Source{})));
+      Source{}, csl_1,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList csl_2;
   csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 0));
   csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
   csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 2));
   csl_2.push_back(create<ast::SintLiteral>(Source{}, &i32, 10));
-  switch_body.push_back(
-      create<ast::CaseStatement>(Source{Source::Location{12, 34}}, csl_2,
-                                 create<ast::BlockStatement>(Source{})));
+  switch_body.push_back(create<ast::CaseStatement>(
+      Source{Source::Location{12, 34}}, csl_2,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{})));
 
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   switch_body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, switch_body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, switch_body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -377,17 +398,20 @@
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod()->RegisterSymbol("a"), "a");
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
-  block_default->append(
-      create<ast::FallthroughStatement>(Source{Source::Location{12, 34}}));
+  auto* block_default = create<ast::BlockStatement>(
+      Source{},
+      ast::StatementList{
+          create<ast::FallthroughStatement>(Source{Source::Location{12, 34}}),
+      });
   ast::CaseStatementList body;
   body.push_back(
       create<ast::CaseStatement>(Source{}, default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(block));
   EXPECT_EQ(v()->error(),
@@ -416,19 +440,22 @@
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod()->RegisterSymbol("a"), "a");
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
                                             default_csl, block_default));
   ast::CaseSelectorList case_csl;
   case_csl.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
-  auto* block_case = create<ast::BlockStatement>(Source{});
+  auto* block_case =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   body.push_back(create<ast::CaseStatement>(Source{}, case_csl, block_case));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, body),
+                });
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
   EXPECT_TRUE(v()->ValidateStatements(block)) << v()->error();
 }
@@ -457,15 +484,17 @@
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod()->RegisterSymbol("a"), "a");
   ast::CaseSelectorList default_csl;
-  auto* block_default = create<ast::BlockStatement>(Source{});
+  auto* block_default =
+      create<ast::BlockStatement>(Source{}, ast::StatementList{});
   ast::CaseStatementList body;
   body.push_back(create<ast::CaseStatement>(Source{Source::Location{12, 34}},
                                             default_csl, block_default));
 
-  auto* block = create<ast::BlockStatement>(Source{});
-  block->append(create<ast::VariableDeclStatement>(Source{}, var));
-  block->append(create<ast::SwitchStatement>(Source{}, cond, body));
-
+  auto* block = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::SwitchStatement>(Source{}, cond, body),
+                });
   mod()->AddConstructedType(&my_int);
 
   EXPECT_TRUE(td()->DetermineStatements(block)) << td()->error();
diff --git a/src/validator/validator_function_test.cc b/src/validator/validator_function_test.cc
index 50420bc..561caf5 100644
--- a/src/validator/validator_function_test.cc
+++ b/src/validator/validator_function_test.cc
@@ -52,8 +52,10 @@
 
   ast::VariableList params;
   ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                });
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
       params, &void_type, body,
@@ -74,7 +76,8 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &void_type, create<ast::BlockStatement>(Source{}),
+      params, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}),
       });
@@ -101,8 +104,10 @@
 
   ast::VariableList params;
   ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                });
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
       params, &i32, body, ast::FunctionDecorationList{});
@@ -121,7 +126,7 @@
   ast::VariableList params;
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
-      params, &i32, create<ast::BlockStatement>(Source{}),
+      params, &i32, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{});
   mod()->AddFunction(func);
 
@@ -137,8 +142,10 @@
   ast::type::Void void_type;
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body,
       ast::FunctionDecorationList{
@@ -155,12 +162,15 @@
   ast::type::Void void_type;
   ast::type::I32 i32;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
   auto* return_expr = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  body->append(create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
-                                            return_expr));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{Source::Location{12, 34}}, return_expr),
+                });
+
   auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
                                      "func", params, &void_type, body,
                                      ast::FunctionDecorationList{});
@@ -179,12 +189,15 @@
   ast::type::I32 i32;
   ast::type::F32 f32;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
   auto* return_expr = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  body->append(create<ast::ReturnStatement>(Source{Source::Location{12, 34}},
-                                            return_expr));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{Source::Location{12, 34}}, return_expr),
+                });
+
   auto* func =
       create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
                             params, &f32, body, ast::FunctionDecorationList{});
@@ -205,21 +218,25 @@
   ast::type::I32 i32;
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
   auto* return_expr = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  body->append(create<ast::ReturnStatement>(Source{}, return_expr));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}, return_expr),
+                });
   auto* func =
       create<ast::Function>(Source{}, mod()->RegisterSymbol("func"), "func",
                             params, &i32, body, ast::FunctionDecorationList{});
 
   ast::VariableList params_copy;
-  auto* body_copy = create<ast::BlockStatement>(Source{});
   auto* return_expr_copy = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
+  auto* body_copy = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}, return_expr_copy),
+                });
 
-  body_copy->append(create<ast::ReturnStatement>(Source{}, return_expr_copy));
   auto* func_copy = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("func"), "func",
       params_copy, &i32, body_copy, ast::FunctionDecorationList{});
@@ -243,9 +260,11 @@
                                         "func"),
       call_params);
   ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(Source{});
-  body0->append(create<ast::CallStatement>(Source{}, call_expr));
-  body0->append(create<ast::ReturnStatement>(Source{}));
+  auto* body0 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::CallStatement>(Source{}, call_expr),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
                                       "func", params0, &f32, body0,
                                       ast::FunctionDecorationList{});
@@ -275,12 +294,15 @@
                             ast::VariableDecorationList{});  // decorations
 
   ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(Source{});
-  body0->append(create<ast::VariableDeclStatement>(Source{}, var));
   auto* return_expr = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  body0->append(create<ast::ReturnStatement>(Source{}, return_expr));
+  auto* body0 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::ReturnStatement>(Source{}, return_expr),
+                });
+
   auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func"),
                                       "func", params0, &i32, body0,
                                       ast::FunctionDecorationList{});
@@ -299,8 +321,10 @@
   auto* return_expr = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 0));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}, return_expr));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}, return_expr),
+                });
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_main"),
       "vtx_main", params, &i32, body,
@@ -329,8 +353,10 @@
                             false,                            // is_const
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("vtx_func"),
       "vtx_func", params, &void_type, body,
@@ -352,8 +378,10 @@
   // fn main() -> void { return; }
   ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("main"), "main",
       params, &void_type, body,
@@ -375,8 +403,10 @@
   // fn vtx_func() -> void { return; }
   ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
       &void_type, body,
@@ -393,8 +423,10 @@
   // fn vtx_func() -> void { return; }
   ast::type::Void void_type;
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("vtx_func"), "vtx_func", params,
       &void_type, body, ast::FunctionDecorationList{});
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index 765ebee..876fb83 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -103,9 +103,11 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_FALSE(td()->DetermineStatements(body));
   EXPECT_EQ(td()->error(),
@@ -199,10 +201,12 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -234,10 +238,12 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.3f));
 
-  ast::BlockStatement block(Source{});
-  block.append(create<ast::VariableDeclStatement>(Source{}, var));
-  block.append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  ast::BlockStatement block(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(&block)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -339,9 +345,11 @@
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
                                      "my_func", params, &f32, body,
@@ -379,10 +387,13 @@
 
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("my_func"), "my_func", params, &void_type,
       body,
@@ -415,19 +426,23 @@
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                });
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{Source::Location{12, 34}}, mod()->RegisterSymbol("a"), "a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.14f));
 
-  auto* outer_body = create<ast::BlockStatement>(Source{});
-  outer_body->append(
-      create<ast::IfStatement>(Source{}, cond, body, ast::ElseStatementList{}));
-  outer_body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* outer_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::IfStatement>(Source{}, cond, body,
+                                             ast::ElseStatementList{}),
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -461,14 +476,19 @@
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
-  auto* outer_body = create<ast::BlockStatement>(Source{});
-  outer_body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  outer_body->append(
-      create<ast::IfStatement>(Source{}, cond, body, ast::ElseStatementList{}));
+  auto* outer_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::IfStatement>(Source{}, cond, body,
+                                             ast::ElseStatementList{}),
+                });
+
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
   ASSERT_NE(rhs->result_type(), nullptr);
@@ -564,10 +584,12 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
@@ -609,9 +631,12 @@
           create<ast::FloatLiteral>(Source{}, &f32, 2.0)),  // constructor
       ast::VariableDecorationList{});                       // decorations
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var),
+                });
+
   auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
                                      "my_func", params, &void_type, body,
                                      ast::FunctionDecorationList{});
@@ -655,10 +680,13 @@
       ast::VariableDecorationList{});                       // decorations
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var_a_float));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var_a_float),
+                });
+
   auto* func = create<ast::Function>(Source{}, mod()->RegisterSymbol("my_func"),
                                      "my_func", params, &void_type, body,
                                      ast::FunctionDecorationList{});
@@ -691,8 +719,10 @@
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                });
 
   auto* var_a_float = create<ast::Variable>(
       Source{},                  // source
@@ -705,11 +735,13 @@
           create<ast::FloatLiteral>(Source{}, &f32, 3.14)),  // constructor
       ast::VariableDecorationList{});                        // decorations
 
-  auto* outer_body = create<ast::BlockStatement>(Source{});
-  outer_body->append(
-      create<ast::IfStatement>(Source{}, cond, body, ast::ElseStatementList{}));
-  outer_body->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var_a_float));
+  auto* outer_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::IfStatement>(Source{}, cond, body,
+                                             ast::ElseStatementList{}),
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var_a_float),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   EXPECT_TRUE(v()->ValidateStatements(outer_body)) << v()->error();
@@ -748,14 +780,18 @@
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var),
+                });
 
-  auto* outer_body = create<ast::BlockStatement>(Source{});
-  outer_body->append(create<ast::VariableDeclStatement>(Source{}, var_a_float));
-  outer_body->append(
-      create<ast::IfStatement>(Source{}, cond, body, ast::ElseStatementList{}));
+  auto* outer_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var_a_float),
+                    create<ast::IfStatement>(Source{}, cond, body,
+                                             ast::ElseStatementList{}),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(outer_body)) << td()->error();
   EXPECT_FALSE(v()->ValidateStatements(outer_body));
@@ -790,19 +826,24 @@
       ast::VariableDecorationList{});                       // decorations
 
   ast::VariableList params0;
-  auto* body0 = create<ast::BlockStatement>(Source{});
-  body0->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var0));
-  body0->append(create<ast::ReturnStatement>(Source{}));
+  auto* body0 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var0),
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   auto* func0 = create<ast::Function>(Source{}, mod()->RegisterSymbol("func0"),
                                       "func0", params0, &void_type, body0,
                                       ast::FunctionDecorationList{});
 
   ast::VariableList params1;
-  auto* body1 = create<ast::BlockStatement>(Source{});
-  body1->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{13, 34}}, var1));
-  body1->append(create<ast::ReturnStatement>(Source{}));
+  auto* body1 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{13, 34}}, var1),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func1 = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("func1"), "func1", params1, &void_type,
       body1,
@@ -838,10 +879,12 @@
   auto* rhs = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::SintLiteral>(Source{}, &i32, 2));
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::AssignmentStatement>(
-      Source{Source::Location{12, 34}}, lhs, rhs));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(Source{}, var),
+                    create<ast::AssignmentStatement>(
+                        Source{Source::Location{12, 34}}, lhs, rhs),
+                });
 
   EXPECT_TRUE(td()->DetermineStatements(body)) << td()->error();
   ASSERT_NE(lhs->result_type(), nullptr);
diff --git a/src/validator/validator_type_test.cc b/src/validator/validator_type_test.cc
index a7f84ae..4950b33 100644
--- a/src/validator/validator_type_test.cc
+++ b/src/validator/validator_type_test.cc
@@ -203,10 +203,11 @@
                             ast::VariableDecorationList{});  // decorations
   ast::VariableList params;
   ast::type::Void void_type;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(
-      Source{Source::Location{12, 34}}, var));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::VariableDeclStatement>(
+                        Source{Source::Location{12, 34}}, var),
+                });
   auto* func = create<ast::Function>(
       Source{}, mod()->RegisterSymbol("func"), "func", params, &void_type, body,
       ast::FunctionDecorationList{
diff --git a/src/writer/hlsl/generator_impl_binary_test.cc b/src/writer/hlsl/generator_impl_binary_test.cc
index 3c52f9d..9b7a4a0 100644
--- a/src/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/writer/hlsl/generator_impl_binary_test.cc
@@ -464,16 +464,22 @@
 
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::ScalarConstructorExpression>(
-                    Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{}, create<ast::ScalarConstructorExpression>(
+                                      Source{}, create<ast::SintLiteral>(
+                                                    Source{}, &i32, 3))),
+                });
   auto* else_stmt = create<ast::ElseStatement>(Source{}, nullptr, body);
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::ScalarConstructorExpression>(
-                    Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{}, create<ast::ScalarConstructorExpression>(
+                                      Source{}, create<ast::SintLiteral>(
+                                                    Source{}, &i32, 2))),
+                });
   auto* else_if_stmt = create<ast::ElseStatement>(
       Source{},
       create<ast::BinaryExpression>(
@@ -484,10 +490,13 @@
                                             "c")),
       body);
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::ScalarConstructorExpression>(
-                    Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
+  body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{}, create<ast::ScalarConstructorExpression>(
+                                      Source{}, create<ast::SintLiteral>(
+                                                    Source{}, &i32, 1))),
+                });
 
   ast::IfStatement expr(Source{},
                         create<ast::BinaryExpression>(
@@ -659,10 +668,10 @@
 
   ast::type::Void void_type;
 
-  auto* func = create<ast::Function>(Source{}, mod.RegisterSymbol("foo"), "foo",
-                                     ast::VariableList{}, &void_type,
-                                     create<ast::BlockStatement>(Source{}),
-                                     ast::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("foo"), "foo", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ast::ExpressionList params;
diff --git a/src/writer/hlsl/generator_impl_block_test.cc b/src/writer/hlsl/generator_impl_block_test.cc
index 0186588..c7fa1e2 100644
--- a/src/writer/hlsl/generator_impl_block_test.cc
+++ b/src/writer/hlsl/generator_impl_block_test.cc
@@ -26,9 +26,9 @@
 using HlslGeneratorImplTest_Block = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Block, Emit_Block) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(out, &b)) << gen.error();
@@ -39,9 +39,9 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Block, Emit_Block_WithoutNewline) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitBlock(out, &b)) << gen.error();
diff --git a/src/writer/hlsl/generator_impl_call_test.cc b/src/writer/hlsl/generator_impl_call_test.cc
index 50d06d6..225c962 100644
--- a/src/writer/hlsl/generator_impl_call_test.cc
+++ b/src/writer/hlsl/generator_impl_call_test.cc
@@ -36,10 +36,10 @@
       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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, &call)) << gen.error();
@@ -58,10 +58,10 @@
       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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(pre, out, &call)) << gen.error();
@@ -81,10 +81,10 @@
   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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, 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_case_test.cc b/src/writer/hlsl/generator_impl_case_test.cc
index 55105f8..8970ce9 100644
--- a/src/writer/hlsl/generator_impl_case_test.cc
+++ b/src/writer/hlsl/generator_impl_case_test.cc
@@ -33,9 +33,10 @@
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   ast::CaseStatement c(Source{}, lit, body);
@@ -54,7 +55,9 @@
 
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
-  ast::CaseStatement c(Source{}, lit, create<ast::BlockStatement>(Source{}));
+  ast::CaseStatement c(
+      Source{}, lit,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   gen.increment_indent();
 
@@ -68,9 +71,10 @@
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::FallthroughStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::FallthroughStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   ast::CaseStatement c(Source{}, lit, body);
@@ -87,9 +91,10 @@
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 6));
@@ -106,8 +111,10 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_Default) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseStatement c(Source{}, ast::CaseSelectorList{}, body);
 
   gen.increment_indent();
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 2deaf62..d869cc0 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
@@ -82,20 +82,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -161,20 +162,21 @@
 
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -240,20 +242,21 @@
 
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -318,20 +321,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -393,20 +397,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -463,20 +468,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -540,18 +546,19 @@
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      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* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        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,
       ast::FunctionDecorationList{
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index d1dee24..5668225 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -55,8 +55,10 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -75,8 +77,10 @@
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("GeometryShader"), "GeometryShader",
       ast::VariableList{}, &void_type, body, ast::FunctionDecorationList{});
@@ -116,8 +120,10 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -169,14 +175,16 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -242,18 +250,20 @@
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      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"))));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        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,
@@ -319,9 +329,11 @@
                                             "x")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -397,9 +409,11 @@
                                             "x")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -477,9 +491,11 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -553,9 +569,11 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -615,24 +633,25 @@
 
   mod.AddGlobalVariable(coord_var);
 
-  ast::VariableList params;
-  auto* assign = create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::MemberAccessorExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("coord"), "coord"),
-          create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("b"),
-                                            "b")),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.0f)));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::MemberAccessorExpression>(
+                  Source{},
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod.RegisterSymbol("coord"), "coord"),
+                  create<ast::IdentifierExpression>(
+                      Source{}, mod.RegisterSymbol("b"), "b")),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.0f))),
+          create<ast::ReturnStatement>(Source{}),
+      });
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(assign);
-  body->append(create<ast::ReturnStatement>(Source{}));
   auto* func = create<ast::Function>(
-      Source{}, mod.RegisterSymbol("frag_main"), "frag_main", params,
-      &void_type, body,
+      Source{}, mod.RegisterSymbol("frag_main"), "frag_main",
+      ast::VariableList{}, &void_type, body,
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
@@ -711,22 +730,25 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("val"),
-                                        "val"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("param"),
-                                        "param")));
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("foo"), "foo")));
+      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{});
@@ -737,17 +759,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
       ast::FunctionDecorationList{
@@ -814,10 +839,13 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("param"), "param")));
+  auto* body = create<ast::BlockStatement>(
+      Source{},
+      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{});
@@ -828,17 +856,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("depth"),
-                                        "depth"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
       ast::FunctionDecorationList{
@@ -913,20 +944,23 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       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"))));
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("param"), "param")));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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{});
@@ -937,17 +971,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("depth"),
-                                        "depth"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
       ast::FunctionDecorationList{
@@ -1013,14 +1050,18 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(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* 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{});
@@ -1044,9 +1085,12 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -1107,14 +1151,18 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(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* 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{});
@@ -1138,9 +1186,12 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -1187,29 +1238,33 @@
   td.RegisterVariableForTesting(bar_var);
   mod.AddGlobalVariable(bar_var);
 
+  auto* list = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))));
+      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::SintLiteral>(Source{}, &i32, 1)),
+                  create<ast::ScalarConstructorExpression>(
+                      Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+              list, ast::ElseStatementList{}),
+          create<ast::ReturnStatement>(Source{}),
+      });
 
-  auto* list = create<ast::BlockStatement>(Source{});
-  list->append(create<ast::ReturnStatement>(Source{}));
-
-  body->append(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{}));
-
-  body->append(create<ast::ReturnStatement>(Source{}));
   auto* func_1 = create<ast::Function>(
       Source{}, mod.RegisterSymbol("ep_1"), "ep_1", params, &void_type, body,
       ast::FunctionDecorationList{
@@ -1242,7 +1297,8 @@
 
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("GeometryShader"), "GeometryShader",
-      ast::VariableList{}, &void_type, create<ast::BlockStatement>(Source{}),
+      ast::VariableList{}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
@@ -1261,8 +1317,11 @@
   ast::type::Void void_type;
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("main"), "main", params, &void_type, body,
       ast::FunctionDecorationList{
@@ -1286,8 +1345,11 @@
   ast::type::Void void_type;
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("main"), "main", params, &void_type, body,
       ast::FunctionDecorationList{
@@ -1323,8 +1385,10 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -1407,9 +1471,12 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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{
@@ -1436,9 +1503,12 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
+    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{
diff --git a/src/writer/hlsl/generator_impl_if_test.cc b/src/writer/hlsl/generator_impl_if_test.cc
index 664a76a..0b1105c 100644
--- a/src/writer/hlsl/generator_impl_if_test.cc
+++ b/src/writer/hlsl/generator_impl_if_test.cc
@@ -29,9 +29,10 @@
 TEST_F(HlslGeneratorImplTest_If, Emit_If) {
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(Source{}, cond, body, ast::ElseStatementList{});
   gen.increment_indent();
 
@@ -45,14 +46,17 @@
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElseIf) {
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, else_cond, else_body)});
@@ -71,14 +75,17 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElse) {
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, nullptr, else_body)});
@@ -98,17 +105,22 @@
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
-  auto* else_body_2 = create<ast::BlockStatement>(Source{});
-  else_body_2->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body_2 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {
diff --git a/src/writer/hlsl/generator_impl_loop_test.cc b/src/writer/hlsl/generator_impl_loop_test.cc
index c413a52..bbd3a4e 100644
--- a/src/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/writer/hlsl/generator_impl_loop_test.cc
@@ -34,9 +34,10 @@
 using HlslGeneratorImplTest_Loop = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_Loop) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, {});
   gen.increment_indent();
 
@@ -48,12 +49,14 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, continuing);
   gen.increment_indent();
 
@@ -75,24 +78,29 @@
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
   ast::type::F32 f32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* inner = create<ast::LoopStatement>(Source{}, body, continuing);
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(inner);
+  body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                   inner,
+                                               });
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("lhs"), "lhs");
   auto* rhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("rhs"), "rhs");
 
-  continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
+  continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
 
   ast::LoopStatement outer(Source{}, body, continuing);
   gen.increment_indent();
@@ -157,26 +165,30 @@
           create<ast::FloatLiteral>(Source{}, &f32, 2.4)),  // constructor
       ast::VariableDecorationList{});                       // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::VariableDeclStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "other",                           // name
-                            ast::StorageClass::kFunction,      // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                      // source
+                            "other",                       // name
+                            ast::StorageClass::kFunction,  // storage_class
+                            &f32,                          // type
+                            false,                         // is_const
+                            nullptr,                       // constructor
+                            ast::VariableDecorationList{})),
+      });
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("lhs"), "lhs");
   auto* rhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("rhs"), "rhs");
 
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   ast::LoopStatement outer(Source{}, body, continuing);
   gen.increment_indent();
 
diff --git a/src/writer/hlsl/generator_impl_switch_test.cc b/src/writer/hlsl/generator_impl_switch_test.cc
index aed1833..6bbec6a 100644
--- a/src/writer/hlsl/generator_impl_switch_test.cc
+++ b/src/writer/hlsl/generator_impl_switch_test.cc
@@ -31,8 +31,10 @@
 using HlslGeneratorImplTest_Switch = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch) {
-  auto* def_body = create<ast::BlockStatement>(Source{});
-  def_body->append(create<ast::BreakStatement>(Source{}));
+  auto* def_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   auto* def =
       create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, def_body);
 
@@ -40,8 +42,10 @@
   ast::CaseSelectorList case_val;
   case_val.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
 
-  auto* case_body = create<ast::BlockStatement>(Source{});
-  case_body->append(create<ast::BreakStatement>(Source{}));
+  auto* case_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
   auto* case_stmt = create<ast::CaseStatement>(Source{}, case_val, case_body);
 
diff --git a/src/writer/hlsl/generator_impl_test.cc b/src/writer/hlsl/generator_impl_test.cc
index 19931af..db93f62 100644
--- a/src/writer/hlsl/generator_impl_test.cc
+++ b/src/writer/hlsl/generator_impl_test.cc
@@ -29,10 +29,10 @@
 
 TEST_F(HlslGeneratorImplTest, 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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ASSERT_TRUE(gen.Generate(out)) << gen.error();
diff --git a/src/writer/msl/generator_impl_block_test.cc b/src/writer/msl/generator_impl_block_test.cc
index a7b8ec3..f50bb3e 100644
--- a/src/writer/msl/generator_impl_block_test.cc
+++ b/src/writer/msl/generator_impl_block_test.cc
@@ -28,9 +28,9 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Block) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(&b)) << gen.error();
@@ -41,9 +41,9 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Block_WithoutNewline) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitBlock(&b)) << gen.error();
diff --git a/src/writer/msl/generator_impl_call_test.cc b/src/writer/msl/generator_impl_call_test.cc
index 4092f73..85efb04 100644
--- a/src/writer/msl/generator_impl_call_test.cc
+++ b/src/writer/msl/generator_impl_call_test.cc
@@ -38,10 +38,10 @@
       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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(&call)) << gen.error();
@@ -60,10 +60,10 @@
       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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   ASSERT_TRUE(gen.EmitExpression(&call)) << gen.error();
@@ -83,10 +83,10 @@
   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::FunctionDecorationList{});
+  auto* func = create<ast::Function>(
+      Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
   mod.AddFunction(func);
 
   gen.increment_indent();
diff --git a/src/writer/msl/generator_impl_case_test.cc b/src/writer/msl/generator_impl_case_test.cc
index f8570c6..cf868c8 100644
--- a/src/writer/msl/generator_impl_case_test.cc
+++ b/src/writer/msl/generator_impl_case_test.cc
@@ -35,9 +35,10 @@
 TEST_F(MslGeneratorImplTest, Emit_Case) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   ast::CaseStatement c(Source{}, lit, body);
@@ -56,7 +57,9 @@
 
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
-  ast::CaseStatement c(Source{}, lit, create<ast::BlockStatement>(Source{}));
+  ast::CaseStatement c(
+      Source{}, lit,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   gen.increment_indent();
 
@@ -70,9 +73,10 @@
 TEST_F(MslGeneratorImplTest, Emit_Case_WithFallthrough) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::FallthroughStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::FallthroughStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   ast::CaseStatement c(Source{}, lit, body);
@@ -89,9 +93,10 @@
 TEST_F(MslGeneratorImplTest, Emit_Case_MultipleSelectors) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 6));
@@ -108,8 +113,10 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Case_Default) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseStatement c(Source{}, ast::CaseSelectorList{}, body);
 
   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 2d2c628..49dd561 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
@@ -81,20 +81,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -157,20 +158,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -233,19 +235,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
+  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,
       ast::FunctionDecorationList{
@@ -308,20 +312,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -381,20 +386,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -449,20 +455,21 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar")));
-
+  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,
       ast::FunctionDecorationList{
@@ -524,18 +531,19 @@
 
   ast::VariableList params;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      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* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        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,
       ast::FunctionDecorationList{
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index e4bf9dc..c328b9e 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -58,8 +58,11 @@
 TEST_F(MslGeneratorImplTest, Emit_Function) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -80,8 +83,11 @@
 TEST_F(MslGeneratorImplTest, Emit_Function_Name_Collision) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -123,8 +129,11 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -177,15 +186,16 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  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,
@@ -253,19 +263,20 @@
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      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"))));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        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,
@@ -330,10 +341,11 @@
                                             "x")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  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,
@@ -411,10 +423,11 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  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,
@@ -497,10 +510,11 @@
                                             "b")),  // constructor
       ast::VariableDecorationList{});               // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  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,
@@ -588,22 +602,25 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("foo"),
-                                        "foo")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("val"),
-                                        "val"),
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("param"),
-                                        "param")));
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("foo"), "foo")));
+      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{});
@@ -614,17 +631,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
       ast::FunctionDecorationList{
@@ -694,10 +714,13 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("param"), "param")));
+  auto* body = create<ast::BlockStatement>(
+      Source{},
+      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{});
@@ -708,17 +731,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("depth"),
-                                        "depth"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
@@ -797,20 +823,23 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       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"))));
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod.RegisterSymbol("param"), "param")));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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{});
@@ -821,17 +850,20 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f)));
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("depth"),
-                                        "depth"),
-      create<ast::CallExpression>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, mod.RegisterSymbol("sub_func"), "sub_func"),
-          expr)));
-  body->append(create<ast::ReturnStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              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,
       ast::FunctionDecorationList{
@@ -895,14 +927,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(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* 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{});
@@ -926,9 +961,11 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -1004,14 +1041,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(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* 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, &f32, body,
       ast::FunctionDecorationList{});
@@ -1035,9 +1075,11 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -1119,14 +1161,17 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(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* 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, &f32, body,
       ast::FunctionDecorationList{});
@@ -1150,9 +1195,11 @@
           expr),                       // constructor
       ast::VariableDecorationList{});  // decorations
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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,
@@ -1207,28 +1254,31 @@
   mod.AddGlobalVariable(bar_var);
 
   ast::VariableList params;
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* list = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
+
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod.RegisterSymbol("bar"),
-                                        "bar"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))));
-
-  auto* list = create<ast::BlockStatement>(Source{});
-  list->append(create<ast::ReturnStatement>(Source{}));
-
-  body->append(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{}));
-
-  body->append(create<ast::ReturnStatement>(Source{}));
+      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::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,
@@ -1264,7 +1314,7 @@
 
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("main"), "main", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}),
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}),
       });
@@ -1296,8 +1346,11 @@
 
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
+  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{});
@@ -1384,10 +1437,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
@@ -1414,10 +1468,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
diff --git a/src/writer/msl/generator_impl_if_test.cc b/src/writer/msl/generator_impl_if_test.cc
index 3ded7e3..772dee9 100644
--- a/src/writer/msl/generator_impl_if_test.cc
+++ b/src/writer/msl/generator_impl_if_test.cc
@@ -31,9 +31,10 @@
 TEST_F(MslGeneratorImplTest, Emit_If) {
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(Source{}, cond, body, ast::ElseStatementList{});
 
   gen.increment_indent();
@@ -48,14 +49,17 @@
 TEST_F(MslGeneratorImplTest, Emit_IfWithElseIf) {
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, else_cond, else_body)});
@@ -72,14 +76,17 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_IfWithElse) {
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, nullptr, else_body)});
@@ -99,17 +106,22 @@
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
-  auto* else_body_2 = create<ast::BlockStatement>(Source{});
-  else_body_2->append(create<ast::ReturnStatement>(Source{}));
+  auto* else_body_2 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {
diff --git a/src/writer/msl/generator_impl_loop_test.cc b/src/writer/msl/generator_impl_loop_test.cc
index 94ecdb5..b8b0a29 100644
--- a/src/writer/msl/generator_impl_loop_test.cc
+++ b/src/writer/msl/generator_impl_loop_test.cc
@@ -36,9 +36,10 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Loop) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, {});
 
   gen.increment_indent();
@@ -51,12 +52,14 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, continuing);
 
   gen.increment_indent();
@@ -79,24 +82,29 @@
 TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
   ast::type::F32 f32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   auto* inner = create<ast::LoopStatement>(Source{}, body, continuing);
 
-  body = create<ast::BlockStatement>(Source{});
-  body->append(inner);
+  body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                   inner,
+                                               });
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("lhs"), "lhs");
   auto* rhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("rhs"), "rhs");
 
-  continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
+  continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
 
   ast::LoopStatement outer(Source{}, body, continuing);
 
@@ -162,26 +170,30 @@
           create<ast::FloatLiteral>(Source{}, &f32, 2.4)),  // constructor
       ast::VariableDecorationList{});                       // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::VariableDeclStatement>(Source{}, var));
-  body->append(create<ast::VariableDeclStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "other",                           // name
-                            ast::StorageClass::kFunction,      // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(Source{}, var),
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                         // source
+                            "other",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{})),  // decorations
+      });
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("lhs"), "lhs");
   auto* rhs = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("rhs"), "rhs");
 
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(Source{}, lhs, rhs));
-
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(Source{}, lhs, rhs),
+                });
   gen.increment_indent();
 
   ast::LoopStatement outer(Source{}, body, continuing);
diff --git a/src/writer/msl/generator_impl_switch_test.cc b/src/writer/msl/generator_impl_switch_test.cc
index 0b82567..eb7f766 100644
--- a/src/writer/msl/generator_impl_switch_test.cc
+++ b/src/writer/msl/generator_impl_switch_test.cc
@@ -33,8 +33,10 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Switch) {
-  auto* def_body = create<ast::BlockStatement>(Source{});
-  def_body->append(create<ast::BreakStatement>(Source{}));
+  auto* def_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   auto* def =
       create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, def_body);
 
@@ -42,8 +44,10 @@
   ast::CaseSelectorList case_val;
   case_val.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
 
-  auto* case_body = create<ast::BlockStatement>(Source{});
-  case_body->append(create<ast::BreakStatement>(Source{}));
+  auto* case_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
   auto* case_stmt = create<ast::CaseStatement>(Source{}, case_val, case_body);
 
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index 10cd631..72e0cd3 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -52,7 +52,7 @@
 
   auto* func = create<ast::Function>(
       Source{}, mod.RegisterSymbol("my_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}),
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}),
       });
diff --git a/src/writer/spirv/builder_block_test.cc b/src/writer/spirv/builder_block_test.cc
index 30dc6ba..3f8e8ae 100644
--- a/src/writer/spirv/builder_block_test.cc
+++ b/src/writer/spirv/builder_block_test.cc
@@ -39,48 +39,51 @@
 
   // Note, this test uses shadow variables which aren't allowed in WGSL but
   // serves to prove the block code is pushing new scopes as needed.
-  ast::BlockStatement outer(Source{});
-
-  outer.append(create<ast::VariableDeclStatement>(
+  auto* inner = create<ast::BlockStatement>(
       Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "var",                             // name
-                            ast::StorageClass::kFunction,      // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
-  outer.append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                      // source
+                            "var",                         // name
+                            ast::StorageClass::kFunction,  // storage_class
+                            &f32,                          // type
+                            false,                         // is_const
+                            nullptr,                       // constructor
+                            ast::VariableDecorationList{})),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("var"), "var"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.0f))),
+      });  // decorations
+  ast::BlockStatement outer(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("var"),
-                                        "var"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))));
-
-  auto* inner = create<ast::BlockStatement>(Source{});
-  inner->append(create<ast::VariableDeclStatement>(
-      Source{},
-      create<ast::Variable>(Source{},                          // source
-                            "var",                             // name
-                            ast::StorageClass::kFunction,      // storage_class
-                            &f32,                              // type
-                            false,                             // is_const
-                            nullptr,                           // constructor
-                            ast::VariableDecorationList{})));  // decorations
-  inner->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("var"),
-                                        "var"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 2.0f))));
-
-  outer.append(inner);
-  outer.append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("var"),
-                                        "var"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.0f))));
+      ast::StatementList{
+          create<ast::VariableDeclStatement>(
+              Source{}, create<ast::Variable>(
+                            Source{},                         // source
+                            "var",                            // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{})),  // decorations
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("var"), "var"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 1.0f))),
+          inner,
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(
+                  Source{}, mod->RegisterSymbol("var"), "var"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::FloatLiteral>(Source{}, &f32, 3.0f))),
+      });
 
   ASSERT_TRUE(td.DetermineResultType(&outer)) << td.error();
 
diff --git a/src/writer/spirv/builder_call_test.cc b/src/writer/spirv/builder_call_test.cc
index de09ffb..76f4fd6 100644
--- a/src/writer/spirv/builder_call_test.cc
+++ b/src/writer/spirv/builder_call_test.cc
@@ -61,20 +61,24 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::BinaryExpression>(
-                    Source{}, ast::BinaryOp::kAdd,
-                    create<ast::IdentifierExpression>(
-                        Source{}, mod->RegisterSymbol("a"), "a"),
-                    create<ast::IdentifierExpression>(
-                        Source{}, mod->RegisterSymbol("b"), "b"))));
+  auto* body = create<ast::BlockStatement>(
+      Source{},
+      ast::StatementList{
+          create<ast::ReturnStatement>(
+              Source{}, create<ast::BinaryExpression>(
+                            Source{}, ast::BinaryOp::kAdd,
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("a"), "a"),
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("b"), "b"))),
+      });
   ast::Function a_func(Source{}, mod->RegisterSymbol("a_func"), "a_func",
                        func_params, &f32, body, ast::FunctionDecorationList{});
 
-  ast::Function func(Source{}, mod->RegisterSymbol("main"), "main", {},
-                     &void_type, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ast::ExpressionList call_params;
   call_params.push_back(create<ast::ScalarConstructorExpression>(
@@ -144,22 +148,25 @@
                             nullptr,                          // constructor
                             ast::VariableDecorationList{}));  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::BinaryExpression>(
-                    Source{}, ast::BinaryOp::kAdd,
-                    create<ast::IdentifierExpression>(
-                        Source{}, mod->RegisterSymbol("a"), "a"),
-                    create<ast::IdentifierExpression>(
-                        Source{}, mod->RegisterSymbol("b"), "b"))));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{},
+      ast::StatementList{
+          create<ast::ReturnStatement>(
+              Source{}, create<ast::BinaryExpression>(
+                            Source{}, ast::BinaryOp::kAdd,
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("a"), "a"),
+                            create<ast::IdentifierExpression>(
+                                Source{}, mod->RegisterSymbol("b"), "b"))),
+      });
   ast::Function a_func(Source{}, mod->RegisterSymbol("a_func"), "a_func",
                        func_params, &void_type, body,
                        ast::FunctionDecorationList{});
 
-  ast::Function func(Source{}, mod->RegisterSymbol("main"), "main", {},
-                     &void_type, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ast::ExpressionList call_params;
   call_params.push_back(create<ast::ScalarConstructorExpression>(
diff --git a/src/writer/spirv/builder_function_decoration_test.cc b/src/writer/spirv/builder_function_decoration_test.cc
index c9f1725..6ca5f03 100644
--- a/src/writer/spirv/builder_function_decoration_test.cc
+++ b/src/writer/spirv/builder_function_decoration_test.cc
@@ -43,7 +43,7 @@
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}),
       });
@@ -68,11 +68,12 @@
 
   ast::type::Void void_type;
 
-  ast::Function func(Source{}, mod->RegisterSymbol("main"), "main", {},
-                     &void_type, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{
-                         create<ast::StageDecoration>(params.stage, Source{}),
-                     });
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{
+          create<ast::StageDecoration>(params.stage, Source{}),
+      });
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -99,7 +100,7 @@
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}),
       });
@@ -163,26 +164,29 @@
   ast::type::F32 f32;
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_out"),
-                                        "my_out"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_in"),
-                                        "my_in")));
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_wg"),
-                                        "my_wg"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_wg"),
-                                        "my_wg")));
-  // Add duplicate usages so we show they don't get output multiple times.
-  body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_out"),
-                                        "my_out"),
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("my_in"),
-                                        "my_in")));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_out"), "my_out"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_in"), "my_in")),
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_wg"), "my_wg"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_wg"), "my_wg")),
+                    // Add duplicate usages so we show they don't get output
+                    // multiple times.
+                    create<ast::AssignmentStatement>(
+                        Source{},
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_out"), "my_out"),
+                        create<ast::IdentifierExpression>(
+                            Source{}, mod->RegisterSymbol("my_in"), "my_in")),
+                });
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type, body,
@@ -256,7 +260,7 @@
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
@@ -272,7 +276,7 @@
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}),
       });
@@ -288,7 +292,7 @@
 
   ast::Function func(
       Source{}, mod->RegisterSymbol("main"), "main", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::WorkgroupDecoration>(2u, 4u, 6u, Source{}),
           create<ast::StageDecoration>(ast::PipelineStage::kCompute, Source{}),
@@ -305,14 +309,14 @@
 
   ast::Function func1(
       Source{}, mod->RegisterSymbol("main1"), "main1", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
 
   ast::Function func2(
       Source{}, mod->RegisterSymbol("main2"), "main2", {}, &void_type,
-      create<ast::BlockStatement>(Source{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{
           create<ast::StageDecoration>(ast::PipelineStage::kFragment, Source{}),
       });
diff --git a/src/writer/spirv/builder_function_test.cc b/src/writer/spirv/builder_function_test.cc
index 04a5a95..c386df2 100644
--- a/src/writer/spirv/builder_function_test.cc
+++ b/src/writer/spirv/builder_function_test.cc
@@ -47,9 +47,10 @@
 
 TEST_F(BuilderTest, Function_Empty) {
   ast::type::Void void_type;
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &void_type, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func));
   EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
@@ -65,9 +66,10 @@
 TEST_F(BuilderTest, Function_Terminator_Return) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
                      &void_type, body, ast::FunctionDecorationList{});
 
@@ -96,10 +98,12 @@
                             ast::VariableDecorationList{});  // decorations
   td.RegisterVariableForTesting(var_a);
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod->RegisterSymbol("a"), "a")));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{}, create<ast::IdentifierExpression>(
+                                      Source{}, mod->RegisterSymbol("a"), "a")),
+                });
   ASSERT_TRUE(td.DetermineResultType(body)) << td.error();
 
   ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
@@ -126,9 +130,10 @@
 TEST_F(BuilderTest, Function_Terminator_Discard) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
                      &void_type, body, ast::FunctionDecorationList{});
 
@@ -166,10 +171,12 @@
                             ast::VariableDecorationList{}),  // decorations
   };
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(
-      Source{}, create<ast::IdentifierExpression>(
-                    Source{}, mod->RegisterSymbol("a"), "a")));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(
+                        Source{}, create<ast::IdentifierExpression>(
+                                      Source{}, mod->RegisterSymbol("a"), "a")),
+                });
   ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", params,
                      &f32, body, ast::FunctionDecorationList{});
 
@@ -196,9 +203,10 @@
 TEST_F(BuilderTest, Function_WithBody) {
   ast::type::Void void_type;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
                      &void_type, body, ast::FunctionDecorationList{});
 
@@ -215,9 +223,10 @@
 
 TEST_F(BuilderTest, FunctionType) {
   ast::type::Void void_type;
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &void_type, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func));
   EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
@@ -227,12 +236,14 @@
 
 TEST_F(BuilderTest, FunctionType_DeDuplicate) {
   ast::type::Void void_type;
-  ast::Function func1(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                      &void_type, create<ast::BlockStatement>(Source{}),
-                      ast::FunctionDecorationList{});
-  ast::Function func2(Source{}, mod->RegisterSymbol("b_func"), "b_func", {},
-                      &void_type, create<ast::BlockStatement>(Source{}),
-                      ast::FunctionDecorationList{});
+  ast::Function func1(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
+  ast::Function func2(
+      Source{}, mod->RegisterSymbol("b_func"), "b_func", {}, &void_type,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func1));
   ASSERT_TRUE(b.GenerateFunction(&func2));
@@ -309,10 +320,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
@@ -340,10 +352,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
diff --git a/src/writer/spirv/builder_if_test.cc b/src/writer/spirv/builder_if_test.cc
index b5c8b8b..65af67c 100644
--- a/src/writer/spirv/builder_if_test.cc
+++ b/src/writer/spirv/builder_if_test.cc
@@ -48,8 +48,10 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  ast::IfStatement expr(Source{}, cond, create<ast::BlockStatement>(Source{}),
-                        ast::ElseStatementList{});
+  ast::IfStatement expr(
+      Source{}, cond,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::ElseStatementList{});
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
@@ -84,14 +86,16 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
@@ -140,21 +144,26 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
+  auto* else_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
 
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
@@ -211,21 +220,26 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
+  auto* else_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
 
   auto* else_cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
@@ -294,34 +308,46 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-  auto* elseif_1_body = create<ast::BlockStatement>(Source{});
-  elseif_1_body->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
+  auto* elseif_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
-  auto* elseif_2_body = create<ast::BlockStatement>(Source{});
-  elseif_2_body->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
+  auto* elseif_2_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 4))));
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 4))),
+      });
+  auto* else_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 5))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 5))),
+      });
 
   auto* elseif_1_cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
@@ -398,17 +424,21 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  auto* if_body = create<ast::BlockStatement>(Source{});
-  if_body->append(create<ast::BreakStatement>(Source{}));
+  auto* if_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
   auto* if_stmt = create<ast::IfStatement>(Source{}, cond, if_body,
                                            ast::ElseStatementList{});
 
-  auto* loop_body = create<ast::BlockStatement>(Source{});
-  loop_body->append(if_stmt);
+  auto* loop_body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                              if_stmt,
+                                                          });
 
-  ast::LoopStatement expr(Source{}, loop_body,
-                          create<ast::BlockStatement>(Source{}));
+  ast::LoopStatement expr(
+      Source{}, loop_body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
@@ -447,19 +477,24 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::BreakStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
   auto* if_stmt = create<ast::IfStatement>(
-      Source{}, cond, create<ast::BlockStatement>(Source{}),
+      Source{}, cond,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::ElseStatementList{
           create<ast::ElseStatement>(Source{}, nullptr, else_body)});
 
-  auto* loop_body = create<ast::BlockStatement>(Source{});
-  loop_body->append(if_stmt);
+  auto* loop_body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                              if_stmt,
+                                                          });
 
-  ast::LoopStatement expr(Source{}, loop_body,
-                          create<ast::BlockStatement>(Source{}));
+  ast::LoopStatement expr(
+      Source{}, loop_body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
@@ -499,17 +534,21 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  auto* if_body = create<ast::BlockStatement>(Source{});
-  if_body->append(create<ast::ContinueStatement>(Source{}));
+  auto* if_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ContinueStatement>(Source{}),
+                });
 
   auto* if_stmt = create<ast::IfStatement>(Source{}, cond, if_body,
                                            ast::ElseStatementList{});
 
-  auto* loop_body = create<ast::BlockStatement>(Source{});
-  loop_body->append(if_stmt);
+  auto* loop_body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                              if_stmt,
+                                                          });
 
-  ast::LoopStatement expr(Source{}, loop_body,
-                          create<ast::BlockStatement>(Source{}));
+  ast::LoopStatement expr(
+      Source{}, loop_body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
@@ -548,19 +587,24 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::ContinueStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ContinueStatement>(Source{}),
+                });
 
   auto* if_stmt = create<ast::IfStatement>(
-      Source{}, cond, create<ast::BlockStatement>(Source{}),
+      Source{}, cond,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::ElseStatementList{
           create<ast::ElseStatement>(Source{}, nullptr, else_body)});
 
-  auto* loop_body = create<ast::BlockStatement>(Source{});
-  loop_body->append(if_stmt);
+  auto* loop_body = create<ast::BlockStatement>(Source{}, ast::StatementList{
+                                                              if_stmt,
+                                                          });
 
-  ast::LoopStatement expr(Source{}, loop_body,
-                          create<ast::BlockStatement>(Source{}));
+  ast::LoopStatement expr(
+      Source{}, loop_body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
@@ -598,8 +642,10 @@
   auto* cond = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true));
 
-  auto* if_body = create<ast::BlockStatement>(Source{});
-  if_body->append(create<ast::ReturnStatement>(Source{}));
+  auto* if_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}),
+                });
 
   ast::IfStatement expr(Source{}, cond, if_body, ast::ElseStatementList{});
 
@@ -630,8 +676,10 @@
   auto* cond2 = create<ast::ScalarConstructorExpression>(
       Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, false));
 
-  auto* if_body = create<ast::BlockStatement>(Source{});
-  if_body->append(create<ast::ReturnStatement>(Source{}, cond2));
+  auto* if_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ReturnStatement>(Source{}, cond2),
+                });
 
   ast::IfStatement expr(Source{}, cond, if_body, ast::ElseStatementList{});
 
@@ -669,11 +717,12 @@
                             ast::VariableDecorationList{});  // decorations
   td.RegisterVariableForTesting(var);
 
-  ast::IfStatement expr(Source{},
-                        create<ast::IdentifierExpression>(
-                            Source{}, mod->RegisterSymbol("a"), "a"),
-                        create<ast::BlockStatement>(Source{}),
-                        ast::ElseStatementList{});
+  ast::IfStatement expr(
+      Source{},
+      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("a"),
+                                        "a"),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::ElseStatementList{});
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index 83d1f61..1d4b8a0 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -471,9 +471,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
@@ -505,9 +506,10 @@
   auto expr = Call(param.name, 1.0f);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -533,9 +535,10 @@
   auto expr = Call(param.name, vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -587,9 +590,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -612,9 +616,10 @@
   auto expr = Call("length", vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -639,9 +644,10 @@
   auto expr = Call("normalize", vec2<f32>(1.0f, 1.0f));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -671,9 +677,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -700,9 +707,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -737,9 +745,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -763,9 +772,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -792,9 +802,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -823,9 +834,10 @@
   auto expr = Call(param.name, 1.0f, 1.0f, 1.0f);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -853,9 +865,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -894,9 +907,10 @@
   auto expr = Call(param.name, 1);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -922,9 +936,10 @@
   auto expr = Call(param.name, vec2<i32>(1, 1));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -957,9 +972,10 @@
   auto expr = Call(param.name, 1u);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -985,9 +1001,10 @@
   auto expr = Call(param.name, vec2<u32>(1u, 1u));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1020,9 +1037,10 @@
   auto expr = Call(param.name, 1, 1);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1048,9 +1066,10 @@
   auto expr = Call(param.name, vec2<i32>(1, 1), vec2<i32>(1, 1));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1084,9 +1103,10 @@
   auto expr = Call(param.name, 1u, 1u);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1112,9 +1132,10 @@
   auto expr = Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(1u, 1u));
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1148,9 +1169,10 @@
   auto expr = Call(param.name, 1, 1, 1);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1178,9 +1200,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1213,9 +1236,10 @@
   auto expr = Call(param.name, 1u, 1u, 1u);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1243,9 +1267,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1276,9 +1301,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
 
@@ -1321,9 +1347,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
@@ -1362,9 +1389,10 @@
 
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
@@ -1409,9 +1437,10 @@
   auto expr = Call("arrayLength", "ptr_var");
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     ty.void_, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, ty.void_,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateFunction(&func)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
diff --git a/src/writer/spirv/builder_loop_test.cc b/src/writer/spirv/builder_loop_test.cc
index 5943521..cf6fa6b 100644
--- a/src/writer/spirv/builder_loop_test.cc
+++ b/src/writer/spirv/builder_loop_test.cc
@@ -39,8 +39,9 @@
   // loop {
   // }
 
-  ast::LoopStatement loop(Source{}, create<ast::BlockStatement>(Source{}),
-                          create<ast::BlockStatement>(Source{}));
+  ast::LoopStatement loop(
+      Source{}, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&loop)) << td.error();
   b.push_function(Function{});
@@ -74,16 +75,19 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-
-  ast::LoopStatement loop(Source{}, body,
-                          create<ast::BlockStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
+  ast::LoopStatement loop(
+      Source{}, body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   td.RegisterVariableForTesting(var);
   ASSERT_TRUE(td.DetermineResultType(&loop)) << td.error();
@@ -130,21 +134,26 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::AssignmentStatement>(
+  auto* body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::AssignmentStatement>(
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
+  auto* continuing = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
   ast::LoopStatement loop(Source{}, body, continuing);
 
   td.RegisterVariableForTesting(var);
@@ -180,11 +189,13 @@
   // loop {
   //   continue;
   // }
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::ContinueStatement>(Source{}));
-
-  ast::LoopStatement loop(Source{}, body,
-                          create<ast::BlockStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::ContinueStatement>(Source{}),
+                });
+  ast::LoopStatement loop(
+      Source{}, body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&loop)) << td.error();
 
@@ -208,11 +219,13 @@
   // loop {
   //   break;
   // }
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
-  ast::LoopStatement loop(Source{}, body,
-                          create<ast::BlockStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
+  ast::LoopStatement loop(
+      Source{}, body,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}));
 
   ASSERT_TRUE(td.DetermineResultType(&loop)) << td.error();
 
diff --git a/src/writer/spirv/builder_switch_test.cc b/src/writer/spirv/builder_switch_test.cc
index 3e99d19..efc1355 100644
--- a/src/writer/spirv/builder_switch_test.cc
+++ b/src/writer/spirv/builder_switch_test.cc
@@ -93,21 +93,27 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* case_1_body = create<ast::BlockStatement>(Source{});
-  case_1_body->append(create<ast::AssignmentStatement>(
+  auto* case_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+      });
 
-  auto* case_2_body = create<ast::BlockStatement>(Source{});
-  case_2_body->append(create<ast::AssignmentStatement>(
+  auto* case_2_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
 
   ast::CaseSelectorList selector_1;
   selector_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
@@ -130,9 +136,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
@@ -195,13 +202,16 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* default_body = create<ast::BlockStatement>(Source{});
-  default_body->append(create<ast::AssignmentStatement>(
+  auto* default_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+      });
 
   ast::CaseStatementList cases;
   cases.push_back(create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{},
@@ -216,9 +226,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
@@ -279,29 +290,38 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* case_1_body = create<ast::BlockStatement>(Source{});
-  case_1_body->append(create<ast::AssignmentStatement>(
+  auto* case_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+      });
 
-  auto* case_2_body = create<ast::BlockStatement>(Source{});
-  case_2_body->append(create<ast::AssignmentStatement>(
+  auto* case_2_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
 
-  auto* default_body = create<ast::BlockStatement>(Source{});
-  default_body->append(create<ast::AssignmentStatement>(
+  auto* default_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
 
   ast::CaseSelectorList selector_1;
   selector_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
@@ -327,9 +347,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
@@ -399,30 +420,38 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* case_1_body = create<ast::BlockStatement>(Source{});
-  case_1_body->append(create<ast::AssignmentStatement>(
+  auto* case_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
-  case_1_body->append(create<ast::FallthroughStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+          create<ast::FallthroughStatement>(Source{})});
 
-  auto* case_2_body = create<ast::BlockStatement>(Source{});
-  case_2_body->append(create<ast::AssignmentStatement>(
+  auto* case_2_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 2))),
+      });
 
-  auto* default_body = create<ast::BlockStatement>(Source{});
-  default_body->append(create<ast::AssignmentStatement>(
+  auto* default_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 3))),
+      });
 
   ast::CaseSelectorList selector_1;
   selector_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
@@ -447,9 +476,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
@@ -515,14 +545,16 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* case_1_body = create<ast::BlockStatement>(Source{});
-  case_1_body->append(create<ast::AssignmentStatement>(
+  auto* case_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
-  case_1_body->append(create<ast::FallthroughStatement>(Source{}));
+      ast::StatementList{
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))),
+          create<ast::FallthroughStatement>(Source{})});
 
   ast::CaseSelectorList selector_1;
   selector_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
@@ -540,9 +572,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
@@ -581,22 +614,26 @@
                             nullptr,                         // constructor
                             ast::VariableDecorationList{});  // decorations
 
-  auto* if_body = create<ast::BlockStatement>(Source{});
-  if_body->append(create<ast::BreakStatement>(Source{}));
+  auto* if_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
-  auto* case_1_body = create<ast::BlockStatement>(Source{});
-  case_1_body->append(create<ast::IfStatement>(
+  auto* case_1_body = create<ast::BlockStatement>(
       Source{},
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::BoolLiteral>(Source{}, &bool_type, true)),
-      if_body, ast::ElseStatementList{}));
-
-  case_1_body->append(create<ast::AssignmentStatement>(
-      Source{},
-      create<ast::IdentifierExpression>(Source{}, mod->RegisterSymbol("v"),
-                                        "v"),
-      create<ast::ScalarConstructorExpression>(
-          Source{}, create<ast::SintLiteral>(Source{}, &i32, 1))));
+      ast::StatementList{
+          create<ast::IfStatement>(
+              Source{},
+              create<ast::ScalarConstructorExpression>(
+                  Source{},
+                  create<ast::BoolLiteral>(Source{}, &bool_type, true)),
+              if_body, ast::ElseStatementList{}),
+          create<ast::AssignmentStatement>(
+              Source{},
+              create<ast::IdentifierExpression>(Source{},
+                                                mod->RegisterSymbol("v"), "v"),
+              create<ast::ScalarConstructorExpression>(
+                  Source{}, create<ast::SintLiteral>(Source{}, &i32, 1)))});
 
   ast::CaseSelectorList selector_1;
   selector_1.push_back(create<ast::SintLiteral>(Source{}, &i32, 1));
@@ -614,9 +651,10 @@
   td.RegisterVariableForTesting(a);
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
 
-  ast::Function func(Source{}, mod->RegisterSymbol("a_func"), "a_func", {},
-                     &i32, create<ast::BlockStatement>(Source{}),
-                     ast::FunctionDecorationList{});
+  ast::Function func(
+      Source{}, mod->RegisterSymbol("a_func"), "a_func", {}, &i32,
+      create<ast::BlockStatement>(Source{}, ast::StatementList{}),
+      ast::FunctionDecorationList{});
 
   ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
diff --git a/src/writer/wgsl/generator_impl_block_test.cc b/src/writer/wgsl/generator_impl_block_test.cc
index b7e88b1..ad15b5d 100644
--- a/src/writer/wgsl/generator_impl_block_test.cc
+++ b/src/writer/wgsl/generator_impl_block_test.cc
@@ -28,9 +28,9 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Block) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitStatement(&b)) << gen.error();
@@ -41,9 +41,9 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Block_WithoutNewline) {
-  ast::BlockStatement b(Source{});
-  b.append(create<ast::DiscardStatement>(Source{}));
-
+  ast::BlockStatement b(Source{}, ast::StatementList{
+                                      create<ast::DiscardStatement>(Source{}),
+                                  });
   gen.increment_indent();
 
   ASSERT_TRUE(gen.EmitBlock(&b)) << gen.error();
diff --git a/src/writer/wgsl/generator_impl_case_test.cc b/src/writer/wgsl/generator_impl_case_test.cc
index 271ab69..aa31215 100644
--- a/src/writer/wgsl/generator_impl_case_test.cc
+++ b/src/writer/wgsl/generator_impl_case_test.cc
@@ -33,9 +33,10 @@
 TEST_F(WgslGeneratorImplTest, Emit_Case) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   ast::CaseStatement c(Source{}, lit, body);
@@ -52,9 +53,10 @@
 TEST_F(WgslGeneratorImplTest, Emit_Case_MultipleSelectors) {
   ast::type::I32 i32;
 
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseSelectorList lit;
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
   lit.push_back(create<ast::SintLiteral>(Source{}, &i32, 6));
@@ -70,8 +72,10 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Case_Default) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::BreakStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   ast::CaseStatement c(Source{}, ast::CaseSelectorList{}, body);
 
   gen.increment_indent();
diff --git a/src/writer/wgsl/generator_impl_function_test.cc b/src/writer/wgsl/generator_impl_function_test.cc
index e47cae5..061a623 100644
--- a/src/writer/wgsl/generator_impl_function_test.cc
+++ b/src/writer/wgsl/generator_impl_function_test.cc
@@ -41,10 +41,11 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Function) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::type::Void void_type;
   ast::Function func(Source{}, mod.RegisterSymbol("my_func"), "my_func", {},
                      &void_type, body, ast::FunctionDecorationList{});
@@ -60,10 +61,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithParams) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::type::F32 f32;
   ast::type::I32 i32;
   ast::VariableList params;
@@ -99,10 +101,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_WorkgroupSize) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::type::Void void_type;
   ast::Function func(Source{}, mod.RegisterSymbol("my_func"), "my_func", {},
                      &void_type, body,
@@ -122,10 +125,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_Stage) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::type::Void void_type;
   ast::Function func(
       Source{}, mod.RegisterSymbol("my_func"), "my_func", {}, &void_type, body,
@@ -145,10 +149,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithDecoration_Multiple) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-  body->append(create<ast::ReturnStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                    create<ast::ReturnStatement>(Source{}),
+                });
   ast::type::Void void_type;
   ast::Function func(
       Source{}, mod.RegisterSymbol("my_func"), "my_func", {}, &void_type, body,
@@ -237,10 +242,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
@@ -267,10 +273,11 @@
                                               "d")),  // constructor
         ast::VariableDecorationList{});               // decorations
 
-    auto* body = create<ast::BlockStatement>(Source{});
-    body->append(create<ast::VariableDeclStatement>(Source{}, var));
-    body->append(create<ast::ReturnStatement>(Source{}));
-
+    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{
diff --git a/src/writer/wgsl/generator_impl_if_test.cc b/src/writer/wgsl/generator_impl_if_test.cc
index 75d0694..38a8f5d 100644
--- a/src/writer/wgsl/generator_impl_if_test.cc
+++ b/src/writer/wgsl/generator_impl_if_test.cc
@@ -30,9 +30,10 @@
 TEST_F(WgslGeneratorImplTest, Emit_If) {
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::IfStatement i(Source{}, cond, body, ast::ElseStatementList{});
 
   gen.increment_indent();
@@ -47,14 +48,17 @@
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::DiscardStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, else_cond, else_body)});
@@ -71,14 +75,17 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::DiscardStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {create<ast::ElseStatement>(Source{}, nullptr, else_body)});
@@ -98,17 +105,22 @@
   auto* else_cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("else_cond"), "else_cond");
 
-  auto* else_body = create<ast::BlockStatement>(Source{});
-  else_body->append(create<ast::DiscardStatement>(Source{}));
+  auto* else_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
 
-  auto* else_body_2 = create<ast::BlockStatement>(Source{});
-  else_body_2->append(create<ast::DiscardStatement>(Source{}));
+  auto* else_body_2 = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
 
   auto* cond = create<ast::IdentifierExpression>(
       Source{}, mod.RegisterSymbol("cond"), "cond");
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::IfStatement i(
       Source{}, cond, body,
       {
diff --git a/src/writer/wgsl/generator_impl_loop_test.cc b/src/writer/wgsl/generator_impl_loop_test.cc
index 4c0b11e..94cc1e1 100644
--- a/src/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/writer/wgsl/generator_impl_loop_test.cc
@@ -28,8 +28,10 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Loop) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, {});
 
   gen.increment_indent();
@@ -42,12 +44,14 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_LoopWithContinuing) {
-  auto* body = create<ast::BlockStatement>(Source{});
-  body->append(create<ast::DiscardStatement>(Source{}));
-
-  auto* continuing = create<ast::BlockStatement>(Source{});
-  continuing->append(create<ast::DiscardStatement>(Source{}));
-
+  auto* body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
+  auto* continuing = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::DiscardStatement>(Source{}),
+                });
   ast::LoopStatement l(Source{}, body, continuing);
 
   gen.increment_indent();
diff --git a/src/writer/wgsl/generator_impl_switch_test.cc b/src/writer/wgsl/generator_impl_switch_test.cc
index f8bd646..495d924 100644
--- a/src/writer/wgsl/generator_impl_switch_test.cc
+++ b/src/writer/wgsl/generator_impl_switch_test.cc
@@ -32,8 +32,10 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Switch) {
-  auto* def_body = create<ast::BlockStatement>(Source{});
-  def_body->append(create<ast::BreakStatement>(Source{}));
+  auto* def_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
   auto* def =
       create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, def_body);
 
@@ -41,8 +43,10 @@
   ast::CaseSelectorList case_val;
   case_val.push_back(create<ast::SintLiteral>(Source{}, &i32, 5));
 
-  auto* case_body = create<ast::BlockStatement>(Source{});
-  case_body->append(create<ast::BreakStatement>(Source{}));
+  auto* case_body = create<ast::BlockStatement>(
+      Source{}, ast::StatementList{
+                    create<ast::BreakStatement>(Source{}),
+                });
 
   auto* case_stmt = create<ast::CaseStatement>(Source{}, case_val, case_body);
 
diff --git a/src/writer/wgsl/generator_impl_test.cc b/src/writer/wgsl/generator_impl_test.cc
index e178013..f2ea0f3 100644
--- a/src/writer/wgsl/generator_impl_test.cc
+++ b/src/writer/wgsl/generator_impl_test.cc
@@ -34,7 +34,7 @@
 
   mod.AddFunction(create<ast::Function>(
       Source{}, mod.RegisterSymbol("a_func"), "my_func", ast::VariableList{},
-      &void_type, create<ast::BlockStatement>(Source{}),
+      &void_type, create<ast::BlockStatement>(Source{}, ast::StatementList{}),
       ast::FunctionDecorationList{}));
 
   ASSERT_TRUE(gen.Generate(mod)) << gen.error();