Convert LoopStatement to use BlockStatement.

This CL converts the LoopStatement class to using a BlockStatement
internally. All usages have been updated execept for the two readers.

Bug: tint:130
Change-Id: Ied4b82f0ef49c7b92caa040bcf73050093022df7
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/25723
Reviewed-by: Sarah Mashayekhi <sarahmashay@google.com>
diff --git a/src/ast/loop_statement.cc b/src/ast/loop_statement.cc
index 69d0a28..33f4ddb 100644
--- a/src/ast/loop_statement.cc
+++ b/src/ast/loop_statement.cc
@@ -17,15 +17,29 @@
 namespace tint {
 namespace ast {
 
-LoopStatement::LoopStatement() : Statement() {}
+LoopStatement::LoopStatement()
+    : Statement(),
+      body_(std::make_unique<BlockStatement>()),
+      continuing_(std::make_unique<BlockStatement>()) {}
 
-LoopStatement::LoopStatement(StatementList body, StatementList continuing)
+LoopStatement::LoopStatement(std::unique_ptr<BlockStatement> body,
+                             std::unique_ptr<BlockStatement> continuing)
     : Statement(), body_(std::move(body)), continuing_(std::move(continuing)) {}
 
 LoopStatement::LoopStatement(const Source& source,
                              StatementList body,
                              StatementList continuing)
     : Statement(source),
+      body_(std::make_unique<BlockStatement>()),
+      continuing_(std::make_unique<BlockStatement>()) {
+  set_body(std::move(body));
+  set_continuing(std::move(continuing));
+}
+
+LoopStatement::LoopStatement(const Source& source,
+                             std::unique_ptr<BlockStatement> body,
+                             std::unique_ptr<BlockStatement> continuing)
+    : Statement(source),
       body_(std::move(body)),
       continuing_(std::move(continuing)) {}
 
@@ -33,18 +47,28 @@
 
 LoopStatement::~LoopStatement() = default;
 
+void LoopStatement::set_body(StatementList body) {
+  for (auto& stmt : body) {
+    body_->append(std::move(stmt));
+  }
+}
+
+void LoopStatement::set_continuing(StatementList continuing) {
+  for (auto& stmt : continuing) {
+    continuing_->append(std::move(stmt));
+  }
+}
+
 bool LoopStatement::IsLoop() const {
   return true;
 }
 
 bool LoopStatement::IsValid() const {
-  for (const auto& stmt : body_) {
-    if (stmt == nullptr || !stmt->IsValid())
-      return false;
+  if (body_ == nullptr || !body_->IsValid()) {
+    return false;
   }
-  for (const auto& stmt : continuing_) {
-    if (stmt == nullptr || !stmt->IsValid())
-      return false;
+  if (continuing_ == nullptr || !continuing_->IsValid()) {
+    return false;
   }
   return true;
 }
@@ -53,15 +77,19 @@
   make_indent(out, indent);
   out << "Loop{" << std::endl;
 
-  for (const auto& stmt : body_)
-    stmt->to_str(out, indent + 2);
+  if (body_ != nullptr) {
+    for (const auto& stmt : *body_) {
+      stmt->to_str(out, indent + 2);
+    }
+  }
 
-  if (continuing_.size() > 0) {
+  if (continuing_ != nullptr && continuing_->size() > 0) {
     make_indent(out, indent + 2);
     out << "continuing {" << std::endl;
 
-    for (const auto& stmt : continuing_)
+    for (const auto& stmt : *continuing_) {
       stmt->to_str(out, indent + 4);
+    }
 
     make_indent(out, indent + 2);
     out << "}" << std::endl;
diff --git a/src/ast/loop_statement.h b/src/ast/loop_statement.h
index 26365da..d46bda2 100644
--- a/src/ast/loop_statement.h
+++ b/src/ast/loop_statement.h
@@ -17,6 +17,7 @@
 
 #include <utility>
 
+#include "src/ast/block_statement.h"
 #include "src/ast/statement.h"
 
 namespace tint {
@@ -30,7 +31,8 @@
   /// Constructor
   /// @param body the body statements
   /// @param continuing the continuing statements
-  LoopStatement(StatementList body, StatementList continuing);
+  LoopStatement(std::unique_ptr<BlockStatement> body,
+                std::unique_ptr<BlockStatement> continuing);
   /// Constructor
   /// @param source the loop statement source
   /// @param body the body statements
@@ -38,25 +40,42 @@
   LoopStatement(const Source& source,
                 StatementList body,
                 StatementList continuing);
+  /// Constructor
+  /// @param source the loop statement source
+  /// @param body the body statements
+  /// @param continuing the continuing statements
+  LoopStatement(const Source& source,
+                std::unique_ptr<BlockStatement> body,
+                std::unique_ptr<BlockStatement> continuing);
   /// Move constructor
   LoopStatement(LoopStatement&&);
   ~LoopStatement() override;
 
   /// Sets the body statements
   /// @param body the body statements
-  void set_body(StatementList body) { body_ = std::move(body); }
+  void set_body(std::unique_ptr<BlockStatement> body) {
+    body_ = std::move(body);
+  }
+  /// Sets the body statements
+  /// @param body the body statements
+  void set_body(StatementList body);
   /// @returns the body statements
-  const StatementList& body() const { return body_; }
+  const BlockStatement* body() const { return body_.get(); }
 
   /// Sets the continuing statements
   /// @param continuing the continuing statements
-  void set_continuing(StatementList continuing) {
+  void set_continuing(std::unique_ptr<BlockStatement> continuing) {
     continuing_ = std::move(continuing);
   }
+  /// Sets the continuing statements
+  /// @param continuing the continuing statements
+  void set_continuing(StatementList continuing);
   /// @returns the continuing statements
-  const StatementList& continuing() const { return continuing_; }
+  const BlockStatement* continuing() const { return continuing_.get(); }
   /// @returns true if there are continuing statements in the loop
-  bool has_continuing() const { return !continuing_.empty(); }
+  bool has_continuing() const {
+    return continuing_ != nullptr && !continuing_->empty();
+  }
 
   /// @returns true if this is a loop statement
   bool IsLoop() const override;
@@ -72,8 +91,8 @@
  private:
   LoopStatement(const LoopStatement&) = delete;
 
-  StatementList body_;
-  StatementList continuing_;
+  std::unique_ptr<BlockStatement> body_;
+  std::unique_ptr<BlockStatement> continuing_;
 };
 
 }  // namespace ast
diff --git a/src/ast/loop_statement_test.cc b/src/ast/loop_statement_test.cc
index dfde6f3..bf61292 100644
--- a/src/ast/loop_statement_test.cc
+++ b/src/ast/loop_statement_test.cc
@@ -28,27 +28,27 @@
 using LoopStatementTest = testing::Test;
 
 TEST_F(LoopStatementTest, Creation) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
-  auto* b_ptr = body[0].get();
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
+  auto* b_ptr = body->last();
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
-  auto* c_ptr = continuing[0].get();
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
+  auto* c_ptr = continuing->last();
 
   LoopStatement l(std::move(body), std::move(continuing));
-  ASSERT_EQ(l.body().size(), 1u);
-  EXPECT_EQ(l.body()[0].get(), b_ptr);
-  ASSERT_EQ(l.continuing().size(), 1u);
-  EXPECT_EQ(l.continuing()[0].get(), c_ptr);
+  ASSERT_EQ(l.body()->size(), 1u);
+  EXPECT_EQ(l.body()->get(0), b_ptr);
+  ASSERT_EQ(l.continuing()->size(), 1u);
+  EXPECT_EQ(l.continuing()->get(0), c_ptr);
 }
 
 TEST_F(LoopStatementTest, Creation_WithSource) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(Source{20, 2}, std::move(body), std::move(continuing));
   auto src = l.source();
@@ -62,99 +62,100 @@
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithoutContinuing) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), {});
   EXPECT_FALSE(l.has_continuing());
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithContinuing) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_TRUE(l.has_continuing());
 }
 
 TEST_F(LoopStatementTest, IsValid) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_WithoutContinuing) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  LoopStatement l(std::move(body), {});
+  LoopStatement l(std::move(body), std::make_unique<BlockStatement>());
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_WithoutBody) {
-  LoopStatement l({}, {});
+  LoopStatement l(std::make_unique<BlockStatement>(),
+                  std::make_unique<BlockStatement>());
   EXPECT_TRUE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_NullBodyStatement) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
-  body.push_back(nullptr);
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
+  body->append(nullptr);
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_InvalidBodyStatement) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
-  body.push_back(std::make_unique<IfStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
+  body->append(std::make_unique<IfStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_NullContinuingStatement) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
-  continuing.push_back(nullptr);
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
+  continuing->append(nullptr);
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, IsValid_InvalidContinuingStatement) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
-  continuing.push_back(std::make_unique<IfStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
+  continuing->append(std::make_unique<IfStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   EXPECT_FALSE(l.IsValid());
 }
 
 TEST_F(LoopStatementTest, ToStr) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), {});
   std::ostringstream out;
@@ -166,11 +167,11 @@
 }
 
 TEST_F(LoopStatementTest, ToStr_WithContinuing) {
-  StatementList body;
-  body.push_back(std::make_unique<DiscardStatement>());
+  auto body = std::make_unique<BlockStatement>();
+  body->append(std::make_unique<DiscardStatement>());
 
-  StatementList continuing;
-  continuing.push_back(std::make_unique<DiscardStatement>());
+  auto continuing = std::make_unique<BlockStatement>();
+  continuing->append(std::make_unique<DiscardStatement>());
 
   LoopStatement l(std::move(body), std::move(continuing));
   std::ostringstream out;
diff --git a/src/reader/wgsl/parser_impl_loop_stmt_test.cc b/src/reader/wgsl/parser_impl_loop_stmt_test.cc
index f602714..f8cc432 100644
--- a/src/reader/wgsl/parser_impl_loop_stmt_test.cc
+++ b/src/reader/wgsl/parser_impl_loop_stmt_test.cc
@@ -27,10 +27,10 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e, nullptr);
 
-  ASSERT_EQ(e->body().size(), 1u);
-  EXPECT_TRUE(e->body()[0]->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsDiscard());
 
-  EXPECT_EQ(e->continuing().size(), 0u);
+  EXPECT_EQ(e->continuing()->size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
@@ -39,11 +39,11 @@
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e, nullptr);
 
-  ASSERT_EQ(e->body().size(), 1u);
-  EXPECT_TRUE(e->body()[0]->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 1u);
+  EXPECT_TRUE(e->body()->get(0)->IsDiscard());
 
-  EXPECT_EQ(e->continuing().size(), 1u);
-  EXPECT_TRUE(e->continuing()[0]->IsDiscard());
+  EXPECT_EQ(e->continuing()->size(), 1u);
+  EXPECT_TRUE(e->continuing()->get(0)->IsDiscard());
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
@@ -51,8 +51,8 @@
   auto e = p->loop_stmt();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e, nullptr);
-  ASSERT_EQ(e->body().size(), 0u);
-  ASSERT_EQ(e->continuing().size(), 0u);
+  ASSERT_EQ(e->body()->size(), 0u);
+  ASSERT_EQ(e->continuing()->size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
@@ -60,9 +60,9 @@
   auto e = p->loop_stmt();
   ASSERT_FALSE(p->has_error()) << p->error();
   ASSERT_NE(e, nullptr);
-  ASSERT_EQ(e->body().size(), 0u);
-  ASSERT_EQ(e->continuing().size(), 1u);
-  EXPECT_TRUE(e->continuing()[0]->IsDiscard());
+  ASSERT_EQ(e->body()->size(), 0u);
+  ASSERT_EQ(e->continuing()->size(), 1u);
+  EXPECT_TRUE(e->continuing()->get(0)->IsDiscard());
 }
 
 TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
diff --git a/src/type_determiner.cc b/src/type_determiner.cc
index fbbc5d5..de26661 100644
--- a/src/type_determiner.cc
+++ b/src/type_determiner.cc
@@ -253,19 +253,6 @@
   return true;
 }
 
-bool TypeDeterminer::DetermineStatements(const ast::StatementList& stmts) {
-  for (const auto& stmt : stmts) {
-    if (!DetermineVariableStorageClass(stmt.get())) {
-      return false;
-    }
-
-    if (!DetermineResultType(stmt.get())) {
-      return false;
-    }
-  }
-  return true;
-}
-
 bool TypeDeterminer::DetermineVariableStorageClass(ast::Statement* stmt) {
   if (!stmt->IsVariableDecl()) {
     return true;
diff --git a/src/type_determiner.h b/src/type_determiner.h
index d7dc0d1..cf8f8bd 100644
--- a/src/type_determiner.h
+++ b/src/type_determiner.h
@@ -65,10 +65,6 @@
   /// @param stmts the statements to check
   /// @returns true if the determination was successful
   bool DetermineStatements(const ast::BlockStatement* stmts);
-  /// Determines type information for a set of statements
-  /// @param stmts the statements to check
-  /// @returns true if the determination was successful
-  bool DetermineStatements(const ast::StatementList& stmts);
   /// Determines type information for a statement
   /// @param stmt the statement to check
   /// @returns true if the determination was successful
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 7aa5ca8..87d0d73 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -278,9 +278,9 @@
       std::make_unique<ast::FloatLiteral>(&f32, 2.3f));
   auto* body_rhs_ptr = body_rhs.get();
 
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::AssignmentStatement>(
-      std::move(body_lhs), std::move(body_rhs)));
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::AssignmentStatement>(std::move(body_lhs),
+                                                          std::move(body_rhs)));
 
   auto continuing_lhs = std::make_unique<ast::ScalarConstructorExpression>(
       std::make_unique<ast::SintLiteral>(&i32, 2));
@@ -290,8 +290,8 @@
       std::make_unique<ast::FloatLiteral>(&f32, 2.3f));
   auto* continuing_rhs_ptr = continuing_rhs.get();
 
-  ast::StatementList continuing;
-  continuing.push_back(std::make_unique<ast::AssignmentStatement>(
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::AssignmentStatement>(
       std::move(continuing_lhs), std::move(continuing_rhs)));
 
   ast::LoopStatement stmt(std::move(body), std::move(continuing));
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 3a3181c..4329e2a 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -1471,9 +1471,9 @@
 
   if (stmt->has_continuing()) {
     make_indent();
-    out_ << "if (!" << guard << ")";
+    out_ << "if (!" << guard << ") ";
 
-    if (!EmitStatementBlockAndNewline(stmt->continuing())) {
+    if (!EmitBlockAndNewline(stmt->continuing())) {
       return false;
     }
 
@@ -1482,7 +1482,7 @@
     out_ << std::endl;
   }
 
-  for (const auto& s : stmt->body()) {
+  for (const auto& s : *(stmt->body())) {
     if (!EmitStatement(s.get())) {
       return false;
     }
@@ -1594,7 +1594,7 @@
   return true;
 }
 
-bool GeneratorImpl::EmitBlockAndNewline(ast::BlockStatement* stmt) {
+bool GeneratorImpl::EmitBlockAndNewline(const ast::BlockStatement* stmt) {
   const bool result = EmitBlock(stmt);
   if (result) {
     out_ << std::endl;
@@ -1611,33 +1611,6 @@
   return result;
 }
 
-bool GeneratorImpl::EmitStatementBlock(const ast::StatementList& statements) {
-  out_ << " {" << std::endl;
-
-  increment_indent();
-
-  for (const auto& s : statements) {
-    if (!EmitStatement(s.get())) {
-      return false;
-    }
-  }
-
-  decrement_indent();
-  make_indent();
-  out_ << "}";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitStatementBlockAndNewline(
-    const ast::StatementList& statements) {
-  const bool result = EmitStatementBlock(statements);
-  if (result) {
-    out_ << std::endl;
-  }
-  return result;
-}
-
 bool GeneratorImpl::EmitStatement(ast::Statement* stmt) {
   if (stmt->IsAssign()) {
     return EmitAssign(stmt->AsAssign());
diff --git a/src/writer/msl/generator_impl.h b/src/writer/msl/generator_impl.h
index 92d0c0b..1a9e0b9 100644
--- a/src/writer/msl/generator_impl.h
+++ b/src/writer/msl/generator_impl.h
@@ -84,7 +84,7 @@
   /// Handles a block statement with a newline at the end
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted successfully
-  bool EmitBlockAndNewline(ast::BlockStatement* stmt);
+  bool EmitBlockAndNewline(const ast::BlockStatement* stmt);
   /// Handles a break statement
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted successfully
@@ -177,14 +177,6 @@
   /// Handles emitting a pipeline stage name
   /// @param stage the stage to emit
   void EmitStage(ast::PipelineStage stage);
-  /// Handles a brace-enclosed list of statements.
-  /// @param statements the statements to output
-  /// @returns true if the statements were emitted
-  bool EmitStatementBlock(const ast::StatementList& statements);
-  /// Handles a brace-enclosed list of statements and trailing newline.
-  /// @param statements the statements to output
-  /// @returns true if the statements were emitted
-  bool EmitStatementBlockAndNewline(const ast::StatementList& statements);
   /// Handles statement
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted
diff --git a/src/writer/msl/generator_impl_loop_test.cc b/src/writer/msl/generator_impl_loop_test.cc
index 049ed51..a44277f 100644
--- a/src/writer/msl/generator_impl_loop_test.cc
+++ b/src/writer/msl/generator_impl_loop_test.cc
@@ -35,8 +35,8 @@
 using MslGeneratorImplTest = testing::Test;
 
 TEST_F(MslGeneratorImplTest, Emit_Loop) {
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::DiscardStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::DiscardStatement>());
 
   ast::LoopStatement l(std::move(body), {});
 
@@ -52,11 +52,11 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::DiscardStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::DiscardStatement>());
 
-  ast::StatementList continuing;
-  continuing.push_back(std::make_unique<ast::ReturnStatement>());
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::ReturnStatement>());
 
   ast::LoopStatement l(std::move(body), std::move(continuing));
 
@@ -82,20 +82,23 @@
 TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
   ast::type::F32Type f32;
 
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::DiscardStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::DiscardStatement>());
 
-  ast::StatementList continuing;
-  continuing.push_back(std::make_unique<ast::ReturnStatement>());
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::ReturnStatement>());
 
   auto inner = std::make_unique<ast::LoopStatement>(std::move(body),
                                                     std::move(continuing));
 
-  body.push_back(std::move(inner));
+  body = std::make_unique<ast::BlockStatement>();
+  body->append(std::move(inner));
 
   auto lhs = std::make_unique<ast::IdentifierExpression>("lhs");
   auto rhs = std::make_unique<ast::IdentifierExpression>("rhs");
-  continuing.push_back(std::make_unique<ast::AssignmentStatement>(
+
+  continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::AssignmentStatement>(
       std::move(lhs), std::move(rhs)));
 
   ast::LoopStatement outer(std::move(body), std::move(continuing));
@@ -138,16 +141,17 @@
   var->set_constructor(std::make_unique<ast::ScalarConstructorExpression>(
       std::make_unique<ast::FloatLiteral>(&f32, 2.4)));
 
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::VariableDeclStatement>(std::move(var)));
-  body.push_back(std::make_unique<ast::VariableDeclStatement>(
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::VariableDeclStatement>(std::move(var)));
+  body->append(std::make_unique<ast::VariableDeclStatement>(
       std::make_unique<ast::Variable>("other", ast::StorageClass::kFunction,
                                       &f32)));
 
-  ast::StatementList continuing;
   auto lhs = std::make_unique<ast::IdentifierExpression>("lhs");
   auto rhs = std::make_unique<ast::IdentifierExpression>("rhs");
-  continuing.push_back(std::make_unique<ast::AssignmentStatement>(
+
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::AssignmentStatement>(
       std::move(lhs), std::move(rhs)));
 
   ast::LoopStatement outer(std::move(body), std::move(continuing));
@@ -172,6 +176,7 @@
   }
 )");
 }
+
 }  // namespace
 }  // namespace msl
 }  // namespace writer
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index a214684..8183daa 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -110,16 +110,6 @@
          last->IsReturn() || last->IsFallthrough();
 }
 
-bool LastIsTerminator(const ast::StatementList& stmts) {
-  if (stmts.empty()) {
-    return false;
-  }
-
-  auto* last = stmts.back().get();
-  return last->IsBreak() || last->IsContinue() || last->IsDiscard() ||
-         last->IsReturn() || last->IsFallthrough();
-}
-
 uint32_t IndexFromName(char name) {
   switch (name) {
     case 'x':
@@ -1794,7 +1784,7 @@
 
   push_function_inst(spv::Op::OpBranch, {Operand::Int(body_block_id)});
   GenerateLabel(body_block_id);
-  if (!GenerateStatementList(stmt->body())) {
+  if (!GenerateBlockStatement(stmt->body())) {
     return false;
   }
 
@@ -1804,7 +1794,7 @@
   }
 
   GenerateLabel(continue_block_id);
-  if (!GenerateStatementList(stmt->continuing())) {
+  if (!GenerateBlockStatement(stmt->continuing())) {
     return false;
   }
   push_function_inst(spv::Op::OpBranch, {Operand::Int(loop_header_id)});
@@ -1817,15 +1807,6 @@
   return true;
 }
 
-bool Builder::GenerateStatementList(const ast::StatementList& list) {
-  for (const auto& inst : list) {
-    if (!GenerateStatement(inst.get())) {
-      return false;
-    }
-  }
-  return true;
-}
-
 bool Builder::GenerateStatement(ast::Statement* stmt) {
   if (stmt->IsAssign()) {
     return GenerateAssignStatement(stmt->AsAssign());
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 2e1a82b..92bc8af 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -315,10 +315,6 @@
   /// @param stmt the statement to generate
   /// @returns true if the statement was generated
   bool GenerateStatement(ast::Statement* stmt);
-  /// Generates a list of statements
-  /// @param list the statement list to generate
-  /// @returns true on successful generation
-  bool GenerateStatementList(const ast::StatementList& list);
   /// Geneates an OpLoad
   /// @param type the type to load
   /// @param id the variable id to load
diff --git a/src/writer/spirv/builder_if_test.cc b/src/writer/spirv/builder_if_test.cc
index 213be80..908ac58 100644
--- a/src/writer/spirv/builder_if_test.cc
+++ b/src/writer/spirv/builder_if_test.cc
@@ -391,10 +391,11 @@
   auto if_stmt =
       std::make_unique<ast::IfStatement>(std::move(cond), std::move(if_body));
 
-  ast::StatementList loop_body;
-  loop_body.push_back(std::move(if_stmt));
+  auto loop_body = std::make_unique<ast::BlockStatement>();
+  loop_body->append(std::move(if_stmt));
 
-  ast::LoopStatement expr(std::move(loop_body), {});
+  ast::LoopStatement expr(std::move(loop_body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
@@ -449,10 +450,11 @@
       std::move(cond), std::make_unique<ast::BlockStatement>());
   if_stmt->set_else_statements(std::move(else_stmts));
 
-  ast::StatementList loop_body;
-  loop_body.push_back(std::move(if_stmt));
+  auto loop_body = std::make_unique<ast::BlockStatement>();
+  loop_body->append(std::move(if_stmt));
 
-  ast::LoopStatement expr(std::move(loop_body), {});
+  ast::LoopStatement expr(std::move(loop_body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
@@ -503,10 +505,11 @@
   auto if_stmt =
       std::make_unique<ast::IfStatement>(std::move(cond), std::move(if_body));
 
-  ast::StatementList loop_body;
-  loop_body.push_back(std::move(if_stmt));
+  auto loop_body = std::make_unique<ast::BlockStatement>();
+  loop_body->append(std::move(if_stmt));
 
-  ast::LoopStatement expr(std::move(loop_body), {});
+  ast::LoopStatement expr(std::move(loop_body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
@@ -561,10 +564,11 @@
       std::move(cond), std::make_unique<ast::BlockStatement>());
   if_stmt->set_else_statements(std::move(else_stmts));
 
-  ast::StatementList loop_body;
-  loop_body.push_back(std::move(if_stmt));
+  auto loop_body = std::make_unique<ast::BlockStatement>();
+  loop_body->append(std::move(if_stmt));
 
-  ast::LoopStatement expr(std::move(loop_body), {});
+  ast::LoopStatement expr(std::move(loop_body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
diff --git a/src/writer/spirv/builder_loop_test.cc b/src/writer/spirv/builder_loop_test.cc
index 1071470..8518eb2 100644
--- a/src/writer/spirv/builder_loop_test.cc
+++ b/src/writer/spirv/builder_loop_test.cc
@@ -72,14 +72,14 @@
   auto var =
       std::make_unique<ast::Variable>("v", ast::StorageClass::kPrivate, &i32);
 
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::AssignmentStatement>(
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::AssignmentStatement>(
       std::make_unique<ast::IdentifierExpression>("v"),
       std::make_unique<ast::ScalarConstructorExpression>(
           std::make_unique<ast::SintLiteral>(&i32, 2))));
 
-  ast::StatementList continuing;
-  ast::LoopStatement expr(std::move(body), std::move(continuing));
+  ast::LoopStatement expr(std::move(body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
@@ -124,14 +124,14 @@
   auto var =
       std::make_unique<ast::Variable>("v", ast::StorageClass::kPrivate, &i32);
 
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::AssignmentStatement>(
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::AssignmentStatement>(
       std::make_unique<ast::IdentifierExpression>("v"),
       std::make_unique<ast::ScalarConstructorExpression>(
           std::make_unique<ast::SintLiteral>(&i32, 2))));
 
-  ast::StatementList continuing;
-  continuing.push_back(std::make_unique<ast::AssignmentStatement>(
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::AssignmentStatement>(
       std::make_unique<ast::IdentifierExpression>("v"),
       std::make_unique<ast::ScalarConstructorExpression>(
           std::make_unique<ast::SintLiteral>(&i32, 3))));
@@ -174,11 +174,11 @@
   // loop {
   //   continue;
   // }
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::ContinueStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::ContinueStatement>());
 
-  ast::StatementList continuing;
-  ast::LoopStatement expr(std::move(body), std::move(continuing));
+  ast::LoopStatement expr(std::move(body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
@@ -206,11 +206,11 @@
   // loop {
   //   break;
   // }
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::BreakStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::BreakStatement>());
 
-  ast::StatementList continuing;
-  ast::LoopStatement expr(std::move(body), std::move(continuing));
+  ast::LoopStatement expr(std::move(body),
+                          std::make_unique<ast::BlockStatement>());
 
   Context ctx;
   ast::Module mod;
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 6da382f..951c78d 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -635,33 +635,6 @@
   return result;
 }
 
-bool GeneratorImpl::EmitStatementBlock(const ast::StatementList& statements) {
-  out_ << " {" << std::endl;
-
-  increment_indent();
-
-  for (const auto& s : statements) {
-    if (!EmitStatement(s.get())) {
-      return false;
-    }
-  }
-
-  decrement_indent();
-  make_indent();
-  out_ << "}";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitStatementBlockAndNewline(
-    const ast::StatementList& statements) {
-  const bool result = EmitStatementBlock(statements);
-  if (result) {
-    out_ << std::endl;
-  }
-  return result;
-}
-
 bool GeneratorImpl::EmitStatement(ast::Statement* stmt) {
   if (stmt->IsAssign()) {
     return EmitAssign(stmt->AsAssign());
@@ -820,7 +793,7 @@
   out_ << "loop {" << std::endl;
   increment_indent();
 
-  for (const auto& s : stmt->body()) {
+  for (const auto& s : *(stmt->body())) {
     if (!EmitStatement(s.get())) {
       return false;
     }
@@ -830,9 +803,9 @@
     out_ << std::endl;
 
     make_indent();
-    out_ << "continuing";
+    out_ << "continuing ";
 
-    if (!EmitStatementBlockAndNewline(stmt->continuing())) {
+    if (!EmitBlockAndNewline(stmt->continuing())) {
       return false;
     }
   }
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index 2f0a500..1c05064 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -159,14 +159,6 @@
   /// @param stmt the statement to emit
   /// @returns true if the statement was successfully emitted
   bool EmitReturn(ast::ReturnStatement* stmt);
-  /// Handles a brace-enclosed list of statements.
-  /// @param statements the statements to output
-  /// @returns true if the statements were emitted
-  bool EmitStatementBlock(const ast::StatementList& statements);
-  /// Handles a brace-enclosed list of statements and trailing newline.
-  /// @param statements the statements to output
-  /// @returns true if the statements were emitted
-  bool EmitStatementBlockAndNewline(const ast::StatementList& statements);
   /// Handles statement
   /// @param stmt the statement to emit
   /// @returns true if the statement was emitted
diff --git a/src/writer/wgsl/generator_impl_loop_test.cc b/src/writer/wgsl/generator_impl_loop_test.cc
index 7b3e92c..e440234 100644
--- a/src/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/writer/wgsl/generator_impl_loop_test.cc
@@ -27,9 +27,8 @@
 using WgslGeneratorImplTest = testing::Test;
 
 TEST_F(WgslGeneratorImplTest, Emit_Loop) {
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::DiscardStatement>());
-
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::DiscardStatement>());
   ast::LoopStatement l(std::move(body), {});
 
   GeneratorImpl g;
@@ -43,11 +42,11 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_LoopWithContinuing) {
-  ast::StatementList body;
-  body.push_back(std::make_unique<ast::DiscardStatement>());
+  auto body = std::make_unique<ast::BlockStatement>();
+  body->append(std::make_unique<ast::DiscardStatement>());
 
-  ast::StatementList continuing;
-  continuing.push_back(std::make_unique<ast::DiscardStatement>());
+  auto continuing = std::make_unique<ast::BlockStatement>();
+  continuing->append(std::make_unique<ast::DiscardStatement>());
 
   ast::LoopStatement l(std::move(body), std::move(continuing));