Unrevert "[ast] Remove unused constructors and setters".

Hopefully the trybot issue is now resolved.

This reverts commit 5792783e72f61060de9cf4a953d5518a56171569,
unreverting commit 4d28b2793512069dc23f88b2804f3594dbd80d45.

Change-Id: I2855bf17c5025a3d349e7fce16fdca342517aad3
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/34564
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/ast/array_accessor_expression.cc b/src/ast/array_accessor_expression.cc
index bfdfddc..7c5900b 100644
--- a/src/ast/array_accessor_expression.cc
+++ b/src/ast/array_accessor_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-ArrayAccessorExpression::ArrayAccessorExpression() : Base() {}
-
 ArrayAccessorExpression::ArrayAccessorExpression(Expression* array,
                                                  Expression* idx_expr)
     : Base(), array_(array), idx_expr_(idx_expr) {}
diff --git a/src/ast/array_accessor_expression.h b/src/ast/array_accessor_expression.h
index 9cc98f7..73cbdac 100644
--- a/src/ast/array_accessor_expression.h
+++ b/src/ast/array_accessor_expression.h
@@ -29,8 +29,6 @@
     : public Castable<ArrayAccessorExpression, Expression> {
  public:
   /// Constructor
-  ArrayAccessorExpression();
-  /// Constructor
   /// @param array the array
   /// @param idx_expr the index expression
   ArrayAccessorExpression(Expression* array, Expression* idx_expr);
@@ -45,9 +43,6 @@
   ArrayAccessorExpression(ArrayAccessorExpression&&);
   ~ArrayAccessorExpression() override;
 
-  /// Sets the array
-  /// @param array the array
-  void set_array(Expression* array) { array_ = array; }
   /// @returns the array
   Expression* array() const { return array_; }
 
diff --git a/src/ast/array_accessor_expression_test.cc b/src/ast/array_accessor_expression_test.cc
index f657815..9526284 100644
--- a/src/ast/array_accessor_expression_test.cc
+++ b/src/ast/array_accessor_expression_test.cc
@@ -43,7 +43,10 @@
 }
 
 TEST_F(ArrayAccessorExpressionTest, IsArrayAccessor) {
-  ArrayAccessorExpression exp;
+  auto* ary = create<IdentifierExpression>("ary");
+  auto* idx = create<IdentifierExpression>("idx");
+
+  ArrayAccessorExpression exp(ary, idx);
   EXPECT_TRUE(exp.Is<ArrayAccessorExpression>());
 }
 
@@ -58,16 +61,14 @@
 TEST_F(ArrayAccessorExpressionTest, IsValid_MissingArray) {
   auto* idx = create<IdentifierExpression>("idx");
 
-  ArrayAccessorExpression exp;
-  exp.set_idx_expr(idx);
+  ArrayAccessorExpression exp(nullptr, idx);
   EXPECT_FALSE(exp.IsValid());
 }
 
 TEST_F(ArrayAccessorExpressionTest, IsValid_MissingIndex) {
   auto* ary = create<IdentifierExpression>("ary");
 
-  ArrayAccessorExpression exp;
-  exp.set_array(ary);
+  ArrayAccessorExpression exp(ary, nullptr);
   EXPECT_FALSE(exp.IsValid());
 }
 
diff --git a/src/ast/assignment_statement.cc b/src/ast/assignment_statement.cc
index 1d89d32..67d0b30 100644
--- a/src/ast/assignment_statement.cc
+++ b/src/ast/assignment_statement.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-AssignmentStatement::AssignmentStatement() : Base() {}
-
 AssignmentStatement::AssignmentStatement(Expression* lhs, Expression* rhs)
     : Base(), lhs_(lhs), rhs_(rhs) {}
 
diff --git a/src/ast/assignment_statement.h b/src/ast/assignment_statement.h
index 2b61bd8..558ae42 100644
--- a/src/ast/assignment_statement.h
+++ b/src/ast/assignment_statement.h
@@ -29,8 +29,6 @@
 class AssignmentStatement : public Castable<AssignmentStatement, Statement> {
  public:
   /// Constructor
-  AssignmentStatement();
-  /// Constructor
   /// @param lhs the left side of the expression
   /// @param rhs the right side of the expression
   AssignmentStatement(Expression* lhs, Expression* rhs);
@@ -43,15 +41,8 @@
   AssignmentStatement(AssignmentStatement&&);
   ~AssignmentStatement() override;
 
-  /// Sets the left side of the statement
-  /// @param lhs the left side to set
-  void set_lhs(Expression* lhs) { lhs_ = lhs; }
   /// @returns the left side expression
   Expression* lhs() const { return lhs_; }
-
-  /// Sets the right side of the statement
-  /// @param rhs the right side to set
-  void set_rhs(Expression* rhs) { rhs_ = rhs; }
   /// @returns the right side expression
   Expression* rhs() const { return rhs_; }
 
diff --git a/src/ast/assignment_statement_test.cc b/src/ast/assignment_statement_test.cc
index b804363..8fa68a4 100644
--- a/src/ast/assignment_statement_test.cc
+++ b/src/ast/assignment_statement_test.cc
@@ -61,16 +61,14 @@
 TEST_F(AssignmentStatementTest, IsValid_MissingLHS) {
   auto* rhs = create<IdentifierExpression>("rhs");
 
-  AssignmentStatement stmt;
-  stmt.set_rhs(rhs);
+  AssignmentStatement stmt(nullptr, rhs);
   EXPECT_FALSE(stmt.IsValid());
 }
 
 TEST_F(AssignmentStatementTest, IsValid_MissingRHS) {
   auto* lhs = create<IdentifierExpression>("lhs");
 
-  AssignmentStatement stmt;
-  stmt.set_lhs(lhs);
+  AssignmentStatement stmt(lhs, nullptr);
   EXPECT_FALSE(stmt.IsValid());
 }
 
diff --git a/src/ast/binary_expression.cc b/src/ast/binary_expression.cc
index 67179e8..edd2e4b 100644
--- a/src/ast/binary_expression.cc
+++ b/src/ast/binary_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-BinaryExpression::BinaryExpression() : Base() {}
-
 BinaryExpression::BinaryExpression(BinaryOp op,
                                    Expression* lhs,
                                    Expression* rhs)
diff --git a/src/ast/binary_expression.h b/src/ast/binary_expression.h
index 783954f..d042e6d 100644
--- a/src/ast/binary_expression.h
+++ b/src/ast/binary_expression.h
@@ -51,8 +51,6 @@
 class BinaryExpression : public Castable<BinaryExpression, Expression> {
  public:
   /// Constructor
-  BinaryExpression();
-  /// Constructor
   /// @param op the operation type
   /// @param lhs the left side of the expression
   /// @param rhs the right side of the expression
@@ -70,9 +68,6 @@
   BinaryExpression(BinaryExpression&&);
   ~BinaryExpression() override;
 
-  /// Sets the binary op type
-  /// @param op the binary op type
-  void set_op(BinaryOp op) { op_ = op; }
   /// @returns the binary op type
   BinaryOp op() const { return op_; }
 
@@ -113,15 +108,8 @@
   /// @returns true if the op is modulo
   bool IsModulo() const { return op_ == BinaryOp::kModulo; }
 
-  /// Sets the left side of the expression
-  /// @param lhs the left side to set
-  void set_lhs(Expression* lhs) { lhs_ = lhs; }
   /// @returns the left side expression
   Expression* lhs() const { return lhs_; }
-
-  /// Sets the right side of the expression
-  /// @param rhs the right side to set
-  void set_rhs(Expression* rhs) { rhs_ = rhs; }
   /// @returns the right side expression
   Expression* rhs() const { return rhs_; }
 
diff --git a/src/ast/binary_expression_test.cc b/src/ast/binary_expression_test.cc
index 2242b24..6494a78 100644
--- a/src/ast/binary_expression_test.cc
+++ b/src/ast/binary_expression_test.cc
@@ -46,8 +46,11 @@
   EXPECT_EQ(src.range.begin.column, 2u);
 }
 
-TEST_F(BinaryExpressionTest, IsBinaryal) {
-  BinaryExpression r;
+TEST_F(BinaryExpressionTest, IsBinary) {
+  auto* lhs = create<IdentifierExpression>("lhs");
+  auto* rhs = create<IdentifierExpression>("rhs");
+
+  BinaryExpression r(BinaryOp::kEqual, lhs, rhs);
   EXPECT_TRUE(r.Is<BinaryExpression>());
 }
 
@@ -62,9 +65,7 @@
 TEST_F(BinaryExpressionTest, IsValid_Null_LHS) {
   auto* rhs = create<IdentifierExpression>("rhs");
 
-  BinaryExpression r;
-  r.set_op(BinaryOp::kEqual);
-  r.set_rhs(rhs);
+  BinaryExpression r(BinaryOp::kEqual, nullptr, rhs);
   EXPECT_FALSE(r.IsValid());
 }
 
@@ -79,9 +80,7 @@
 TEST_F(BinaryExpressionTest, IsValid_Null_RHS) {
   auto* lhs = create<IdentifierExpression>("lhs");
 
-  BinaryExpression r;
-  r.set_op(BinaryOp::kEqual);
-  r.set_lhs(lhs);
+  BinaryExpression r(BinaryOp::kEqual, lhs, nullptr);
   EXPECT_FALSE(r.IsValid());
 }
 
diff --git a/src/ast/bitcast_expression.cc b/src/ast/bitcast_expression.cc
index 50ab4f3..aeca953 100644
--- a/src/ast/bitcast_expression.cc
+++ b/src/ast/bitcast_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-BitcastExpression::BitcastExpression() : Base() {}
-
 BitcastExpression::BitcastExpression(type::Type* type, Expression* expr)
     : Base(), type_(type), expr_(expr) {}
 
diff --git a/src/ast/bitcast_expression.h b/src/ast/bitcast_expression.h
index f736071..b846b73 100644
--- a/src/ast/bitcast_expression.h
+++ b/src/ast/bitcast_expression.h
@@ -29,8 +29,6 @@
 class BitcastExpression : public Castable<BitcastExpression, Expression> {
  public:
   /// Constructor
-  BitcastExpression();
-  /// Constructor
   /// @param type the type
   /// @param expr the expr
   BitcastExpression(type::Type* type, Expression* expr);
@@ -43,15 +41,8 @@
   BitcastExpression(BitcastExpression&&);
   ~BitcastExpression() override;
 
-  /// Sets the type
-  /// @param type the type
-  void set_type(type::Type* type) { type_ = type; }
   /// @returns the left side expression
   type::Type* type() const { return type_; }
-
-  /// Sets the expr
-  /// @param expr the expression
-  void set_expr(Expression* expr) { expr_ = expr; }
   /// @returns the expression
   Expression* expr() const { return expr_; }
 
diff --git a/src/ast/bitcast_expression_test.cc b/src/ast/bitcast_expression_test.cc
index 51d48c9..1c8afc1 100644
--- a/src/ast/bitcast_expression_test.cc
+++ b/src/ast/bitcast_expression_test.cc
@@ -44,7 +44,10 @@
 }
 
 TEST_F(BitcastExpressionTest, IsBitcast) {
-  BitcastExpression exp;
+  type::F32 f32;
+  auto* expr = create<IdentifierExpression>("expr");
+
+  BitcastExpression exp(&f32, expr);
   EXPECT_TRUE(exp.Is<BitcastExpression>());
 }
 
@@ -59,16 +62,14 @@
 TEST_F(BitcastExpressionTest, IsValid_MissingType) {
   auto* expr = create<IdentifierExpression>("expr");
 
-  BitcastExpression exp;
-  exp.set_expr(expr);
+  BitcastExpression exp(nullptr, expr);
   EXPECT_FALSE(exp.IsValid());
 }
 
 TEST_F(BitcastExpressionTest, IsValid_MissingExpr) {
   type::F32 f32;
 
-  BitcastExpression exp;
-  exp.set_type(&f32);
+  BitcastExpression exp(&f32, nullptr);
   EXPECT_FALSE(exp.IsValid());
 }
 
diff --git a/src/ast/call_expression.cc b/src/ast/call_expression.cc
index be19771..17b2acd 100644
--- a/src/ast/call_expression.cc
+++ b/src/ast/call_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-CallExpression::CallExpression() : Base() {}
-
 CallExpression::CallExpression(Expression* func, ExpressionList params)
     : Base(), func_(func), params_(params) {}
 
diff --git a/src/ast/call_expression.h b/src/ast/call_expression.h
index 3c12822..faa8dcb 100644
--- a/src/ast/call_expression.h
+++ b/src/ast/call_expression.h
@@ -28,8 +28,6 @@
 class CallExpression : public Castable<CallExpression, Expression> {
  public:
   /// Constructor
-  CallExpression();
-  /// Constructor
   /// @param func the function
   /// @param params the parameters
   CallExpression(Expression* func, ExpressionList params);
@@ -42,15 +40,8 @@
   CallExpression(CallExpression&&);
   ~CallExpression() override;
 
-  /// Sets the func
-  /// @param func the func
-  void set_func(Expression* func) { func_ = func; }
   /// @returns the func
   Expression* func() const { return func_; }
-
-  /// Sets the parameters
-  /// @param params the parameters
-  void set_params(ExpressionList params) { params_ = params; }
   /// @returns the parameters
   const ExpressionList& params() const { return params_; }
 
diff --git a/src/ast/call_expression_test.cc b/src/ast/call_expression_test.cc
index 0d30953..be84072 100644
--- a/src/ast/call_expression_test.cc
+++ b/src/ast/call_expression_test.cc
@@ -59,7 +59,7 @@
 }
 
 TEST_F(CallExpressionTest, IsValid_MissingFunction) {
-  CallExpression stmt;
+  CallExpression stmt(nullptr, {});
   EXPECT_FALSE(stmt.IsValid());
 }
 
diff --git a/src/ast/call_statement.cc b/src/ast/call_statement.cc
index 4bc7952..d74df3d 100644
--- a/src/ast/call_statement.cc
+++ b/src/ast/call_statement.cc
@@ -23,8 +23,6 @@
 namespace tint {
 namespace ast {
 
-CallStatement::CallStatement() : Base() {}
-
 CallStatement::CallStatement(CallExpression* call) : Base(), call_(call) {}
 
 CallStatement::CallStatement(CallStatement&&) = default;
diff --git a/src/ast/call_statement.h b/src/ast/call_statement.h
index 026e61f..2af7582 100644
--- a/src/ast/call_statement.h
+++ b/src/ast/call_statement.h
@@ -28,17 +28,12 @@
 class CallStatement : public Castable<CallStatement, Statement> {
  public:
   /// Constructor
-  CallStatement();
-  /// Constructor
   /// @param call the function
   explicit CallStatement(CallExpression* call);
   /// Move constructor
   CallStatement(CallStatement&&);
   ~CallStatement() override;
 
-  /// Sets the call expression
-  /// @param call the call
-  void set_expr(CallExpression* call) { call_ = call; }
   /// @returns the call expression
   CallExpression* expr() const { return call_; }
 
diff --git a/src/ast/call_statement_test.cc b/src/ast/call_statement_test.cc
index 4a6a5fe..8a0e7b5 100644
--- a/src/ast/call_statement_test.cc
+++ b/src/ast/call_statement_test.cc
@@ -33,7 +33,7 @@
 }
 
 TEST_F(CallStatementTest, IsCall) {
-  CallStatement c;
+  CallStatement c(nullptr);
   EXPECT_TRUE(c.Is<CallStatement>());
 }
 
@@ -44,12 +44,13 @@
 }
 
 TEST_F(CallStatementTest, IsValid_MissingExpr) {
-  CallStatement c;
+  CallStatement c(nullptr);
   EXPECT_FALSE(c.IsValid());
 }
 
 TEST_F(CallStatementTest, IsValid_InvalidExpr) {
-  CallStatement c(create<CallExpression>());
+  CallExpression stmt(nullptr, {});
+  CallStatement c(&stmt);
   EXPECT_FALSE(c.IsValid());
 }
 
diff --git a/src/ast/case_statement.h b/src/ast/case_statement.h
index 9ed2deb..cea4327 100644
--- a/src/ast/case_statement.h
+++ b/src/ast/case_statement.h
@@ -52,11 +52,6 @@
   CaseStatement(CaseStatement&&);
   ~CaseStatement() override;
 
-  /// Sets the selectors for the case statement
-  /// @param selectors the selectors to set
-  void set_selectors(CaseSelectorList selectors) {
-    selectors_ = std::move(selectors);
-  }
   /// @returns the case selectors, empty if none set
   const CaseSelectorList& selectors() const { return selectors_; }
   /// @returns true if this is a default statement
diff --git a/src/ast/case_statement_test.cc b/src/ast/case_statement_test.cc
index 5600173..ba62191 100644
--- a/src/ast/case_statement_test.cc
+++ b/src/ast/case_statement_test.cc
@@ -82,8 +82,7 @@
   auto* body = create<BlockStatement>();
   body->append(create<DiscardStatement>());
 
-  CaseStatement c(create<BlockStatement>());
-  c.set_body(body);
+  CaseStatement c(body);
   EXPECT_TRUE(c.IsDefault());
 }
 
@@ -92,8 +91,7 @@
   CaseSelectorList b;
   b.push_back(create<SintLiteral>(&i32, 2));
 
-  CaseStatement c(create<BlockStatement>());
-  c.set_selectors(b);
+  CaseStatement c(b, create<BlockStatement>());
   EXPECT_FALSE(c.IsDefault());
 }
 
diff --git a/src/ast/decorated_variable.h b/src/ast/decorated_variable.h
index 7770bed..2e0aeee 100644
--- a/src/ast/decorated_variable.h
+++ b/src/ast/decorated_variable.h
@@ -28,6 +28,7 @@
 class DecoratedVariable : public Castable<DecoratedVariable, Variable> {
  public:
   /// Create a new empty decorated variable statement
+  /// Note, used by the `Clone` method.
   DecoratedVariable();
   /// Create a decorated variable from an existing variable
   /// @param var the variable to initialize from
diff --git a/src/ast/decorated_variable_test.cc b/src/ast/decorated_variable_test.cc
index 63a4340..d31a7cf 100644
--- a/src/ast/decorated_variable_test.cc
+++ b/src/ast/decorated_variable_test.cc
@@ -107,7 +107,8 @@
 }
 
 TEST_F(DecoratedVariableTest, IsDecorated) {
-  DecoratedVariable dv;
+  type::I32 t;
+  DecoratedVariable dv(create<Variable>("my_var", StorageClass::kNone, &t));
   EXPECT_TRUE(dv.Is<DecoratedVariable>());
 }
 
diff --git a/src/ast/else_statement.h b/src/ast/else_statement.h
index 01be9a8..f39a1f0 100644
--- a/src/ast/else_statement.h
+++ b/src/ast/else_statement.h
@@ -51,17 +51,11 @@
   ElseStatement(ElseStatement&&);
   ~ElseStatement() override;
 
-  /// Sets the condition for the else statement
-  /// @param condition the condition to set
-  void set_condition(Expression* condition) { condition_ = condition; }
   /// @returns the else condition or nullptr if none set
   Expression* condition() const { return condition_; }
   /// @returns true if the else has a condition
   bool HasCondition() const { return condition_ != nullptr; }
 
-  /// Sets the else body
-  /// @param body the else body
-  void set_body(BlockStatement* body) { body_ = body; }
   /// @returns the else body
   const BlockStatement* body() const { return body_; }
   /// @returns the else body
diff --git a/src/ast/else_statement_test.cc b/src/ast/else_statement_test.cc
index 40ac0e0..166d805 100644
--- a/src/ast/else_statement_test.cc
+++ b/src/ast/else_statement_test.cc
@@ -90,7 +90,7 @@
 }
 
 TEST_F(ElseStatementTest, IsValid_InvalidCondition) {
-  auto* cond = create<ScalarConstructorExpression>();
+  auto* cond = create<ScalarConstructorExpression>(nullptr);
   ElseStatement e(cond, create<BlockStatement>());
   EXPECT_FALSE(e.IsValid());
 }
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 173f1ed..86a4f30 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -30,8 +30,6 @@
 namespace tint {
 namespace ast {
 
-Function::Function() = default;
-
 Function::Function(const std::string& name,
                    VariableList params,
                    type::Type* return_type,
diff --git a/src/ast/function.h b/src/ast/function.h
index 3ced0ec..dbe02e0 100644
--- a/src/ast/function.h
+++ b/src/ast/function.h
@@ -50,8 +50,7 @@
     SetDecoration* set = nullptr;
   };
 
-  /// Create a new empty function statement
-  Function();  /// Create a function
+  /// Create a function
   /// @param name the function name
   /// @param params the function parameters
   /// @param return_type the return type
@@ -76,15 +75,8 @@
 
   ~Function() override;
 
-  /// Sets the function name
-  /// @param name the name to set
-  void set_name(const std::string& name) { name_ = name; }
   /// @returns the function name
   const std::string& name() { return name_; }
-
-  /// Sets the function parameters
-  /// @param params the function parameters
-  void set_params(VariableList params) { params_ = std::move(params); }
   /// @returns the function params
   const VariableList& params() const { return params_; }
 
diff --git a/src/ast/if_statement_test.cc b/src/ast/if_statement_test.cc
index 45e99ba..a87930a 100644
--- a/src/ast/if_statement_test.cc
+++ b/src/ast/if_statement_test.cc
@@ -67,8 +67,8 @@
   body->append(create<DiscardStatement>());
 
   ElseStatementList else_stmts;
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[0]->set_condition(create<IdentifierExpression>("Ident"));
+  else_stmts.push_back(create<ElseStatement>(
+      create<IdentifierExpression>("Ident"), create<BlockStatement>()));
   else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
 
   IfStatement stmt(cond, body);
@@ -119,8 +119,8 @@
   body->append(create<DiscardStatement>());
 
   ElseStatementList else_stmts;
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[0]->set_condition(create<IdentifierExpression>("Ident"));
+  else_stmts.push_back(create<ElseStatement>(
+      create<IdentifierExpression>("Ident"), create<BlockStatement>()));
   else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
   else_stmts.push_back(nullptr);
 
@@ -135,8 +135,8 @@
   body->append(create<DiscardStatement>());
 
   ElseStatementList else_stmts;
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[0]->set_condition(create<IdentifierExpression>(""));
+  else_stmts.push_back(create<ElseStatement>(create<IdentifierExpression>(""),
+                                             create<BlockStatement>()));
 
   IfStatement stmt(cond, body);
   stmt.set_else_statements(else_stmts);
@@ -164,8 +164,8 @@
 
   ElseStatementList else_stmts;
   else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[1]->set_condition(create<IdentifierExpression>("ident"));
+  else_stmts.push_back(create<ElseStatement>(
+      create<IdentifierExpression>("ident"), create<BlockStatement>()));
 
   IfStatement stmt(cond, body);
   stmt.set_else_statements(else_stmts);
@@ -205,11 +205,9 @@
   else_body->append(create<DiscardStatement>());
 
   ElseStatementList else_stmts;
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[0]->set_condition(create<IdentifierExpression>("ident"));
-  else_stmts[0]->set_body(else_if_body);
-  else_stmts.push_back(create<ElseStatement>(create<BlockStatement>()));
-  else_stmts[1]->set_body(else_body);
+  else_stmts.push_back(create<ElseStatement>(
+      create<IdentifierExpression>("ident"), else_if_body));
+  else_stmts.push_back(create<ElseStatement>(else_body));
 
   IfStatement stmt(cond, body);
   stmt.set_else_statements(else_stmts);
diff --git a/src/ast/location_decoration.h b/src/ast/location_decoration.h
index 560c3d6..dc641e4 100644
--- a/src/ast/location_decoration.h
+++ b/src/ast/location_decoration.h
@@ -29,7 +29,7 @@
   /// constructor
   /// @param value the location value
   /// @param source the source of this decoration
-  explicit LocationDecoration(uint32_t value, const Source& source);
+  LocationDecoration(uint32_t value, const Source& source);
   ~LocationDecoration() override;
 
   /// @returns the location value
diff --git a/src/ast/member_accessor_expression.cc b/src/ast/member_accessor_expression.cc
index 9fdbef3..34f8726 100644
--- a/src/ast/member_accessor_expression.cc
+++ b/src/ast/member_accessor_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-MemberAccessorExpression::MemberAccessorExpression() = default;
-
 MemberAccessorExpression::MemberAccessorExpression(Expression* structure,
                                                    IdentifierExpression* member)
     : Base(), struct_(structure), member_(member) {}
diff --git a/src/ast/member_accessor_expression.h b/src/ast/member_accessor_expression.h
index 4b4f859..3b9b09a 100644
--- a/src/ast/member_accessor_expression.h
+++ b/src/ast/member_accessor_expression.h
@@ -31,8 +31,6 @@
     : public Castable<MemberAccessorExpression, Expression> {
  public:
   /// Constructor
-  MemberAccessorExpression();
-  /// Constructor
   /// @param structure the structure
   /// @param member the member
   MemberAccessorExpression(Expression* structure, IdentifierExpression* member);
@@ -47,15 +45,8 @@
   MemberAccessorExpression(MemberAccessorExpression&&);
   ~MemberAccessorExpression() override;
 
-  /// Sets the structure
-  /// @param structure the structure
-  void set_structure(Expression* structure) { struct_ = structure; }
   /// @returns the structure
   Expression* structure() const { return struct_; }
-
-  /// Sets the member
-  /// @param member the member
-  void set_member(IdentifierExpression* member) { member_ = member; }
   /// @returns the member expression
   IdentifierExpression* member() const { return member_; }
 
diff --git a/src/ast/member_accessor_expression_test.cc b/src/ast/member_accessor_expression_test.cc
index 331157f..d307b80 100644
--- a/src/ast/member_accessor_expression_test.cc
+++ b/src/ast/member_accessor_expression_test.cc
@@ -45,7 +45,10 @@
 }
 
 TEST_F(MemberAccessorExpressionTest, IsMemberAccessor) {
-  MemberAccessorExpression stmt;
+  auto* str = create<IdentifierExpression>("structure");
+  auto* mem = create<IdentifierExpression>("member");
+
+  MemberAccessorExpression stmt(str, mem);
   EXPECT_TRUE(stmt.Is<MemberAccessorExpression>());
 }
 
@@ -60,8 +63,7 @@
 TEST_F(MemberAccessorExpressionTest, IsValid_NullStruct) {
   auto* mem = create<IdentifierExpression>("member");
 
-  MemberAccessorExpression stmt;
-  stmt.set_member(mem);
+  MemberAccessorExpression stmt(nullptr, mem);
   EXPECT_FALSE(stmt.IsValid());
 }
 
@@ -76,8 +78,7 @@
 TEST_F(MemberAccessorExpressionTest, IsValid_NullMember) {
   auto* str = create<IdentifierExpression>("structure");
 
-  MemberAccessorExpression stmt;
-  stmt.set_structure(str);
+  MemberAccessorExpression stmt(str, nullptr);
   EXPECT_FALSE(stmt.IsValid());
 }
 
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
index 0bdbf49..a26b62b 100644
--- a/src/ast/module_test.cc
+++ b/src/ast/module_test.cc
@@ -139,7 +139,8 @@
 }
 
 TEST_F(ModuleTest, IsValid_Invalid_Function) {
-  auto* func = create<Function>();
+  VariableList p;
+  auto* func = create<Function>("", p, nullptr, nullptr);
 
   Module m;
   m.AddFunction(func);
diff --git a/src/ast/scalar_constructor_expression.cc b/src/ast/scalar_constructor_expression.cc
index 23bec02..ba127e8 100644
--- a/src/ast/scalar_constructor_expression.cc
+++ b/src/ast/scalar_constructor_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-ScalarConstructorExpression::ScalarConstructorExpression() : Base() {}
-
 ScalarConstructorExpression::ScalarConstructorExpression(Literal* literal)
     : literal_(literal) {}
 
diff --git a/src/ast/scalar_constructor_expression.h b/src/ast/scalar_constructor_expression.h
index 05ce216..5a3fd65 100644
--- a/src/ast/scalar_constructor_expression.h
+++ b/src/ast/scalar_constructor_expression.h
@@ -29,8 +29,6 @@
     : public Castable<ScalarConstructorExpression, ConstructorExpression> {
  public:
   /// Constructor
-  ScalarConstructorExpression();
-  /// Constructor
   /// @param literal the const literal
   explicit ScalarConstructorExpression(Literal* literal);
   /// Constructor
@@ -41,9 +39,6 @@
   ScalarConstructorExpression(ScalarConstructorExpression&&);
   ~ScalarConstructorExpression() override;
 
-  /// Set the literal value
-  /// @param literal the literal
-  void set_literal(Literal* literal) { literal_ = literal; }
   /// @returns the literal value
   Literal* literal() const { return literal_; }
 
diff --git a/src/ast/scalar_constructor_expression_test.cc b/src/ast/scalar_constructor_expression_test.cc
index 60e4185..0168356 100644
--- a/src/ast/scalar_constructor_expression_test.cc
+++ b/src/ast/scalar_constructor_expression_test.cc
@@ -48,7 +48,7 @@
 }
 
 TEST_F(ScalarConstructorExpressionTest, IsValid_MissingLiteral) {
-  ScalarConstructorExpression c;
+  ScalarConstructorExpression c(nullptr);
   EXPECT_FALSE(c.IsValid());
 }
 
diff --git a/src/ast/struct.cc b/src/ast/struct.cc
index 4297a39..a214209 100644
--- a/src/ast/struct.cc
+++ b/src/ast/struct.cc
@@ -23,8 +23,6 @@
 namespace tint {
 namespace ast {
 
-Struct::Struct() : Base() {}
-
 Struct::Struct(StructMemberList members)
     : Base(), members_(std::move(members)) {}
 
diff --git a/src/ast/struct.h b/src/ast/struct.h
index 0b37d28..ab49a0f 100644
--- a/src/ast/struct.h
+++ b/src/ast/struct.h
@@ -29,8 +29,6 @@
 /// A struct statement.
 class Struct : public Castable<Struct, Node> {
  public:
-  /// Create a new empty struct statement
-  Struct();
   /// Create a new struct statement
   /// @param members The struct members
   explicit Struct(StructMemberList members);
diff --git a/src/ast/struct_member.cc b/src/ast/struct_member.cc
index a040450..68192da 100644
--- a/src/ast/struct_member.cc
+++ b/src/ast/struct_member.cc
@@ -23,8 +23,6 @@
 namespace tint {
 namespace ast {
 
-StructMember::StructMember() = default;
-
 StructMember::StructMember(const std::string& name,
                            type::Type* type,
                            StructMemberDecorationList decorations)
diff --git a/src/ast/struct_member.h b/src/ast/struct_member.h
index a659e87..4064767 100644
--- a/src/ast/struct_member.h
+++ b/src/ast/struct_member.h
@@ -31,8 +31,6 @@
 /// A struct member statement.
 class StructMember : public Castable<StructMember, Node> {
  public:
-  /// Create a new empty struct member statement
-  StructMember();
   /// Create a new struct member statement
   /// @param name The struct member name
   /// @param type The struct member type
@@ -54,14 +52,8 @@
 
   ~StructMember() override;
 
-  /// Sets the name
-  /// @param name the name to set
-  void set_name(const std::string& name) { name_ = name; }
   /// @returns the name
   const std::string& name() const { return name_; }
-  /// Sets the type
-  /// @param type the type to set
-  void set_type(type::Type* type) { type_ = type; }
   /// @returns the type
   type::Type* type() const { return type_; }
   /// Sets the decorations
diff --git a/src/ast/struct_test.cc b/src/ast/struct_test.cc
index 11e9bb8..b615bc8 100644
--- a/src/ast/struct_test.cc
+++ b/src/ast/struct_test.cc
@@ -87,7 +87,7 @@
 }
 
 TEST_F(StructTest, IsValid) {
-  Struct s;
+  Struct s({});
   EXPECT_TRUE(s.IsValid());
 }
 
diff --git a/src/ast/switch_statement.cc b/src/ast/switch_statement.cc
index 01a99e9..8634ed4 100644
--- a/src/ast/switch_statement.cc
+++ b/src/ast/switch_statement.cc
@@ -23,8 +23,6 @@
 namespace tint {
 namespace ast {
 
-SwitchStatement::SwitchStatement() : Base() {}
-
 SwitchStatement::SwitchStatement(Expression* condition, CaseStatementList body)
     : condition_(condition), body_(body) {}
 
diff --git a/src/ast/switch_statement.h b/src/ast/switch_statement.h
index 53c80ca..d44a45f 100644
--- a/src/ast/switch_statement.h
+++ b/src/ast/switch_statement.h
@@ -30,8 +30,6 @@
 class SwitchStatement : public Castable<SwitchStatement, Statement> {
  public:
   /// Constructor
-  SwitchStatement();
-  /// Constructor
   /// @param condition the switch condition
   /// @param body the switch body
   SwitchStatement(Expression* condition, CaseStatementList body);
@@ -46,9 +44,6 @@
   SwitchStatement(SwitchStatement&&);
   ~SwitchStatement() override;
 
-  /// Sets the condition for the switch statement
-  /// @param condition the condition to set
-  void set_condition(Expression* condition) { condition_ = condition; }
   /// @returns the switch condition or nullptr if none set
   Expression* condition() const { return condition_; }
   /// @returns true if this is a default statement
diff --git a/src/ast/switch_statement_test.cc b/src/ast/switch_statement_test.cc
index 14d90e6..df82f3d 100644
--- a/src/ast/switch_statement_test.cc
+++ b/src/ast/switch_statement_test.cc
@@ -56,7 +56,16 @@
 }
 
 TEST_F(SwitchStatementTest, IsSwitch) {
-  SwitchStatement stmt;
+  type::I32 i32;
+
+  CaseSelectorList lit;
+  lit.push_back(create<SintLiteral>(&i32, 2));
+
+  auto* ident = create<IdentifierExpression>("ident");
+  CaseStatementList body;
+  body.push_back(create<CaseStatement>(lit, create<BlockStatement>()));
+
+  SwitchStatement stmt(ident, body);
   EXPECT_TRUE(stmt.Is<SwitchStatement>());
 }
 
@@ -83,8 +92,7 @@
   CaseStatementList body;
   body.push_back(create<CaseStatement>(lit, create<BlockStatement>()));
 
-  SwitchStatement stmt;
-  stmt.set_body(body);
+  SwitchStatement stmt(nullptr, body);
   EXPECT_FALSE(stmt.IsValid());
 }
 
diff --git a/src/ast/type/struct_type_test.cc b/src/ast/type/struct_type_test.cc
index 1a915a2..3dd11f1 100644
--- a/src/ast/type/struct_type_test.cc
+++ b/src/ast/type/struct_type_test.cc
@@ -40,14 +40,16 @@
 using StructTest = TestHelper;
 
 TEST_F(StructTest, Creation) {
-  auto* impl = create<ast::Struct>();
+  StructMemberList members;
+  auto* impl = create<ast::Struct>(members);
   auto* ptr = impl;
   Struct s{"S", impl};
   EXPECT_EQ(s.impl(), ptr);
 }
 
 TEST_F(StructTest, Is) {
-  auto* impl = create<ast::Struct>();
+  StructMemberList members;
+  auto* impl = create<ast::Struct>(members);
   Struct s{"S", impl};
   Type* ty = &s;
   EXPECT_FALSE(ty->Is<AccessControl>());
@@ -66,7 +68,8 @@
 }
 
 TEST_F(StructTest, TypeName) {
-  auto* impl = create<ast::Struct>();
+  StructMemberList members;
+  auto* impl = create<ast::Struct>(members);
   Struct s{"my_struct", impl};
   EXPECT_EQ(s.type_name(), "__struct_my_struct");
 }
diff --git a/src/ast/type_constructor_expression.cc b/src/ast/type_constructor_expression.cc
index bf7dbfe..6710023 100644
--- a/src/ast/type_constructor_expression.cc
+++ b/src/ast/type_constructor_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-TypeConstructorExpression::TypeConstructorExpression() : Base() {}
-
 TypeConstructorExpression::TypeConstructorExpression(type::Type* type,
                                                      ExpressionList values)
     : Base(), type_(type), values_(std::move(values)) {}
diff --git a/src/ast/type_constructor_expression.h b/src/ast/type_constructor_expression.h
index 12b0e97..7f239dc 100644
--- a/src/ast/type_constructor_expression.h
+++ b/src/ast/type_constructor_expression.h
@@ -28,11 +28,10 @@
 class TypeConstructorExpression
     : public Castable<TypeConstructorExpression, ConstructorExpression> {
  public:
-  TypeConstructorExpression();
   /// Constructor
   /// @param type the type
   /// @param values the values
-  explicit TypeConstructorExpression(type::Type* type, ExpressionList values);
+  TypeConstructorExpression(type::Type* type, ExpressionList values);
   /// Constructor
   /// @param source the constructor source
   /// @param type the type
@@ -44,15 +43,8 @@
   TypeConstructorExpression(TypeConstructorExpression&&);
   ~TypeConstructorExpression() override;
 
-  /// Set the type
-  /// @param type the type
-  void set_type(type::Type* type) { type_ = type; }
   /// @returns the type
   type::Type* type() const { return type_; }
-
-  /// Set the values
-  /// @param values the values
-  void set_values(ExpressionList values) { values_ = std::move(values); }
   /// @returns the values
   const ExpressionList& values() const { return values_; }
 
diff --git a/src/ast/type_constructor_expression_test.cc b/src/ast/type_constructor_expression_test.cc
index 477faf5..d7efed7 100644
--- a/src/ast/type_constructor_expression_test.cc
+++ b/src/ast/type_constructor_expression_test.cc
@@ -52,7 +52,11 @@
 }
 
 TEST_F(TypeConstructorExpressionTest, IsTypeConstructor) {
-  TypeConstructorExpression t;
+  type::F32 f32;
+  ExpressionList expr;
+  expr.push_back(create<IdentifierExpression>("expr"));
+
+  TypeConstructorExpression t(&f32, expr);
   EXPECT_TRUE(t.Is<TypeConstructorExpression>());
 }
 
@@ -77,8 +81,7 @@
   ExpressionList expr;
   expr.push_back(create<IdentifierExpression>("expr"));
 
-  TypeConstructorExpression t;
-  t.set_values(expr);
+  TypeConstructorExpression t(nullptr, expr);
   EXPECT_FALSE(t.IsValid());
 }
 
diff --git a/src/ast/unary_op_expression.cc b/src/ast/unary_op_expression.cc
index 9e9ad5d..53d1762 100644
--- a/src/ast/unary_op_expression.cc
+++ b/src/ast/unary_op_expression.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-UnaryOpExpression::UnaryOpExpression() : Base() {}
-
 UnaryOpExpression::UnaryOpExpression(UnaryOp op, Expression* expr)
     : Base(), op_(op), expr_(expr) {}
 
diff --git a/src/ast/unary_op_expression.h b/src/ast/unary_op_expression.h
index d2c5e42..4fbefd5 100644
--- a/src/ast/unary_op_expression.h
+++ b/src/ast/unary_op_expression.h
@@ -29,8 +29,6 @@
 class UnaryOpExpression : public Castable<UnaryOpExpression, Expression> {
  public:
   /// Constructor
-  UnaryOpExpression();
-  /// Constructor
   /// @param op the op
   /// @param expr the expr
   UnaryOpExpression(UnaryOp op, Expression* expr);
@@ -43,15 +41,8 @@
   UnaryOpExpression(UnaryOpExpression&&);
   ~UnaryOpExpression() override;
 
-  /// Sets the op
-  /// @param op the op
-  void set_op(UnaryOp op) { op_ = op; }
   /// @returns the op
   UnaryOp op() const { return op_; }
-
-  /// Sets the expr
-  /// @param expr the expression
-  void set_expr(Expression* expr) { expr_ = expr; }
   /// @returns the expression
   Expression* expr() const { return expr_; }
 
diff --git a/src/ast/unary_op_expression_test.cc b/src/ast/unary_op_expression_test.cc
index ea6e516..5e3ec1f 100644
--- a/src/ast/unary_op_expression_test.cc
+++ b/src/ast/unary_op_expression_test.cc
@@ -42,7 +42,8 @@
 }
 
 TEST_F(UnaryOpExpressionTest, IsUnaryOp) {
-  UnaryOpExpression u;
+  auto* ident = create<IdentifierExpression>("ident");
+  UnaryOpExpression u(UnaryOp::kNot, ident);
   EXPECT_TRUE(u.Is<UnaryOpExpression>());
 }
 
@@ -53,8 +54,7 @@
 }
 
 TEST_F(UnaryOpExpressionTest, IsValid_NullExpression) {
-  UnaryOpExpression u;
-  u.set_op(UnaryOp::kNot);
+  UnaryOpExpression u(UnaryOp::kNot, nullptr);
   EXPECT_FALSE(u.IsValid());
 }
 
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index 53c0f03..dbfe7d5 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -41,11 +41,9 @@
 Variable::~Variable() = default;
 
 Variable* Variable::Clone(CloneContext* ctx) const {
-  auto* cloned = ctx->mod->create<Variable>();
+  auto* cloned =
+      ctx->mod->create<Variable>(name(), storage_class(), ctx->Clone(type()));
   cloned->set_source(ctx->Clone(source()));
-  cloned->set_name(name());
-  cloned->set_storage_class(storage_class());
-  cloned->set_type(ctx->Clone(type()));
   cloned->set_constructor(ctx->Clone(constructor()));
   cloned->set_is_const(is_const());
   return cloned;
diff --git a/src/ast/variable.h b/src/ast/variable.h
index 43fe16c..72de0f1 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -78,8 +78,6 @@
 /// The storage class for a formal parameter is always StorageClass::kNone.
 class Variable : public Castable<Variable, Node> {
  public:
-  /// Create a new empty variable statement
-  Variable();
   /// Create a variable
   /// @param name the variables name
   /// @param sc the variable storage class
@@ -149,6 +147,10 @@
   void to_str(std::ostream& out, size_t indent) const override;
 
  protected:
+  /// Constructor
+  /// Used by the DecoratedVariable constructor.
+  Variable();
+
   /// Output information for this variable.
   /// @param out the stream to write to
   /// @param indent number of spaces to indent the node when writing
diff --git a/src/ast/variable_decl_statement.cc b/src/ast/variable_decl_statement.cc
index fc9763c..83b4b7c 100644
--- a/src/ast/variable_decl_statement.cc
+++ b/src/ast/variable_decl_statement.cc
@@ -22,8 +22,6 @@
 namespace tint {
 namespace ast {
 
-VariableDeclStatement::VariableDeclStatement() : Base() {}
-
 VariableDeclStatement::VariableDeclStatement(Variable* variable)
     : Base(), variable_(variable) {}
 
diff --git a/src/ast/variable_decl_statement.h b/src/ast/variable_decl_statement.h
index bdf5ed2..6ec3748 100644
--- a/src/ast/variable_decl_statement.h
+++ b/src/ast/variable_decl_statement.h
@@ -30,8 +30,6 @@
     : public Castable<VariableDeclStatement, Statement> {
  public:
   /// Constructor
-  VariableDeclStatement();
-  /// Constructor
   /// @param variable the variable
   explicit VariableDeclStatement(Variable* variable);
   /// Constructor
@@ -42,9 +40,6 @@
   VariableDeclStatement(VariableDeclStatement&&);
   ~VariableDeclStatement() override;
 
-  /// Sets the variable
-  /// @param variable the variable to set
-  void set_variable(Variable* variable) { variable_ = variable; }
   /// @returns the variable
   Variable* variable() const { return variable_; }
 
diff --git a/src/ast/variable_decl_statement_test.cc b/src/ast/variable_decl_statement_test.cc
index afd1538..daa7c2a 100644
--- a/src/ast/variable_decl_statement_test.cc
+++ b/src/ast/variable_decl_statement_test.cc
@@ -43,7 +43,10 @@
 }
 
 TEST_F(VariableDeclStatementTest, IsVariableDecl) {
-  VariableDeclStatement s;
+  type::F32 f32;
+  auto* var = create<Variable>("a", StorageClass::kNone, &f32);
+
+  VariableDeclStatement s(var);
   EXPECT_TRUE(s.Is<VariableDeclStatement>());
 }
 
@@ -62,7 +65,7 @@
 }
 
 TEST_F(VariableDeclStatementTest, IsValid_NullVariable) {
-  VariableDeclStatement stmt;
+  VariableDeclStatement stmt(nullptr);
   EXPECT_FALSE(stmt.IsValid());
 }
 
diff --git a/src/ast/variable_test.cc b/src/ast/variable_test.cc
index 0b8bf9b..9f22a94 100644
--- a/src/ast/variable_test.cc
+++ b/src/ast/variable_test.cc
@@ -53,14 +53,9 @@
 }
 
 TEST_F(VariableTest, CreationEmpty) {
-  Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}};
-  Variable v;
-  v.set_source(s);
-  v.set_storage_class(StorageClass::kWorkgroup);
-  v.set_name("a_var");
-
   type::I32 t;
-  v.set_type(&t);
+  Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}};
+  Variable v(s, "a_var", StorageClass::kWorkgroup, &t);
 
   EXPECT_EQ(v.name(), "a_var");
   EXPECT_EQ(v.storage_class(), StorageClass::kWorkgroup);
@@ -96,7 +91,7 @@
 }
 
 TEST_F(VariableTest, IsValid_MissingBoth) {
-  Variable v;
+  Variable v("", StorageClass::kNone, nullptr);
   EXPECT_FALSE(v.IsValid());
 }
 
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 5ea523c..05e0b61 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -2137,12 +2137,13 @@
   assert(construct->begin_id == block_info.id);
   const auto* branch = block_info.basic_block->terminator();
 
-  auto* const switch_stmt =
-      AddStatement(create<ast::SwitchStatement>())->As<ast::SwitchStatement>();
   const auto selector_id = branch->GetSingleWordInOperand(0);
   // Generate the code for the selector.
   auto selector = MakeExpression(selector_id);
-  switch_stmt->set_condition(selector.expr);
+
+  ast::CaseStatementList list;
+  auto* swch = create<ast::SwitchStatement>(selector.expr, list);
+  auto* const switch_stmt = AddStatement(swch)->As<ast::SwitchStatement>();
 
   // First, push the statement block for the entire switch.  All the actual
   // work is done by completion actions of the case/default clauses.
@@ -2194,12 +2195,6 @@
   // Push them on in reverse order.
   const auto last_clause_index = clause_heads.size() - 1;
   for (size_t i = last_clause_index;; --i) {
-    // Create the case clause.  Temporarily put it in the wrong order
-    // on the case statement list.
-    cases->emplace_back(
-        create<ast::CaseStatement>(create<ast::BlockStatement>()));
-    auto* clause = cases->back();
-
     // Create a list of integer literals for the selector values leading to
     // this case clause.
     ast::CaseSelectorList selectors;
@@ -2220,14 +2215,20 @@
               create<ast::SintLiteral>(selector.type, value32));
         }
       }
-      clause->set_selectors(selectors);
     }
 
     // Where does this clause end?
     const auto end_id = (i + 1 < clause_heads.size()) ? clause_heads[i + 1]->id
                                                       : construct->end_id;
 
+    // Create the case clause.  Temporarily put it in the wrong order
+    // on the case statement list.
+    cases->emplace_back(create<ast::CaseStatement>(selectors, nullptr));
+    auto* clause = cases->back();
+
     PushNewStatementBlock(construct, end_id, [clause](StatementBlock* s) {
+      // The `set_body` method of CaseStatement can be removed if this set
+      // is removed.
       clause->set_body(s->statements_);
     });
 
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 1e169ad..fcbba85 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -1745,14 +1745,13 @@
   auto source = t.source();
   next();  // Consume the peek
 
-  auto* stmt = create<ast::CaseStatement>(create<ast::BlockStatement>());
-  stmt->set_source(source);
+  ast::CaseSelectorList selector_list;
   if (t.IsCase()) {
     auto selectors = expect_case_selectors();
     if (selectors.errored)
       return Failure::kErrored;
 
-    stmt->set_selectors(std::move(selectors.value));
+    selector_list = std::move(selectors.value);
   }
 
   const char* use = "case statement";
@@ -1767,9 +1766,7 @@
   if (!body.matched)
     return add_error(body.source, "expected case body");
 
-  stmt->set_body(body.value);
-
-  return stmt;
+  return create<ast::CaseStatement>(source, selector_list, body.value);
 }
 
 // case_selectors
diff --git a/src/scope_stack_test.cc b/src/scope_stack_test.cc
index f1f5551..f1d8153 100644
--- a/src/scope_stack_test.cc
+++ b/src/scope_stack_test.cc
@@ -14,6 +14,7 @@
 #include "src/scope_stack.h"
 
 #include "gtest/gtest.h"
+#include "src/ast/type/f32_type.h"
 #include "src/ast/variable.h"
 
 namespace tint {
@@ -31,7 +32,8 @@
 }
 
 TEST_F(ScopeStackTest, Global_SetWithPointer) {
-  ast::Variable v;
+  ast::type::F32 f32;
+  ast::Variable v("test", ast::StorageClass::kNone, &f32);
   v.set_name("my_var");
 
   ScopeStack<ast::Variable*> s;
diff --git a/src/writer/hlsl/generator_impl_alias_type_test.cc b/src/writer/hlsl/generator_impl_alias_type_test.cc
index 1aa406a..4a637b5 100644
--- a/src/writer/hlsl/generator_impl_alias_type_test.cc
+++ b/src/writer/hlsl/generator_impl_alias_type_test.cc
@@ -50,8 +50,7 @@
   ast::type::I32 i32;
   ast::type::F32 f32;
 
-  auto* str = create<ast::Struct>();
-  str->set_members({
+  auto* str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>("a", &f32, ast::StructMemberDecorationList{}),
       create<ast::StructMember>(
           "b", &i32,
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index db623f6..487230e 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -279,8 +279,7 @@
   members.push_back(create<ast::StructMember>(
       "coord", &vec4, ast::StructMemberDecorationList{}));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Uniforms", str);
 
@@ -345,8 +344,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
@@ -404,8 +402,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadOnly, &s);
@@ -463,8 +460,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 145e0c7..516d397 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -54,8 +54,7 @@
   deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
   members.push_back(create<ast::StructMember>("mem", &f32, deco));
 
-  auto* strct = create<ast::Struct>();
-  strct->set_members(members);
+  auto* strct = create<ast::Struct>(members);
 
   ast::type::Struct s("Str", strct);
 
@@ -98,8 +97,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -142,8 +140,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -180,8 +177,7 @@
   ast::type::I32 i32;
   ast::type::Matrix mat(&f32, 3, 2);
 
-  auto* str = create<ast::Struct>();
-  str->set_members({
+  auto* str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "z", &i32,
           ast::StructMemberDecorationList{
@@ -249,8 +245,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("a", &mat, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -305,8 +300,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("a", &mat, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -356,8 +350,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("a", &mat, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -399,8 +392,7 @@
   deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
   members.push_back(create<ast::StructMember>("a", &mat, deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -446,8 +438,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(16, Source{}));
   members.push_back(create<ast::StructMember>("a", &mat, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -494,8 +485,7 @@
   a_deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
   members.push_back(create<ast::StructMember>("a", &ary, a_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -539,8 +529,7 @@
   a_deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
   members.push_back(create<ast::StructMember>("a", &ary, a_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -596,8 +585,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -643,8 +631,7 @@
   a_deco.push_back(create<ast::StructMemberOffsetDecoration>(0, Source{}));
   members.push_back(create<ast::StructMember>("a", &ary, a_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -696,8 +683,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -748,8 +734,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(16, Source{}));
   members.push_back(create<ast::StructMember>("b", &fvec3, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -795,8 +780,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(16, Source{}));
   members.push_back(create<ast::StructMember>("b", &fvec3, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
 
@@ -851,8 +835,7 @@
   ast::type::Vector ivec3(&i32, 3);
   ast::type::Vector fvec3(&f32, 3);
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -868,8 +851,7 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({
+  auto* pre_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "c", &ary,
           ast::StructMemberDecorationList{
@@ -924,8 +906,7 @@
   ast::StructMemberList members;
   ast::StructMemberDecorationList deco;
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -941,11 +922,11 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({create<ast::StructMember>(
-      "c", &ary,
-      ast::StructMemberDecorationList{
-          create<ast::StructMemberOffsetDecoration>(0, Source{})})});
+  auto* pre_str =
+      create<ast::Struct>(ast::StructMemberList{create<ast::StructMember>(
+          "c", &ary,
+          ast::StructMemberDecorationList{
+              create<ast::StructMemberOffsetDecoration>(0, Source{})})});
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
@@ -995,8 +976,7 @@
   ast::type::Vector ivec3(&i32, 3);
   ast::type::Vector fvec3(&f32, 3);
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -1012,11 +992,11 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({create<ast::StructMember>(
-      "c", &ary,
-      ast::StructMemberDecorationList{
-          create<ast::StructMemberOffsetDecoration>(0, Source{})})});
+  auto* pre_str =
+      create<ast::Struct>(ast::StructMemberList{create<ast::StructMember>(
+          "c", &ary,
+          ast::StructMemberDecorationList{
+              create<ast::StructMemberOffsetDecoration>(0, Source{})})});
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
@@ -1065,8 +1045,7 @@
   ast::type::Vector ivec3(&i32, 3);
   ast::type::Vector fvec3(&f32, 3);
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -1082,11 +1061,11 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({create<ast::StructMember>(
-      "c", &ary,
-      ast::StructMemberDecorationList{
-          create<ast::StructMemberOffsetDecoration>(0, Source{})})});
+  auto* pre_str =
+      create<ast::Struct>(ast::StructMemberList{create<ast::StructMember>(
+          "c", &ary,
+          ast::StructMemberDecorationList{
+              create<ast::StructMemberOffsetDecoration>(0, Source{})})});
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
@@ -1136,8 +1115,7 @@
   ast::type::Vector ivec3(&i32, 3);
   ast::type::Vector fvec3(&f32, 3);
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -1153,11 +1131,11 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({create<ast::StructMember>(
-      "c", &ary,
-      ast::StructMemberDecorationList{
-          create<ast::StructMemberOffsetDecoration>(0, Source{})})});
+  auto* pre_str =
+      create<ast::Struct>(ast::StructMemberList{create<ast::StructMember>(
+          "c", &ary,
+          ast::StructMemberDecorationList{
+              create<ast::StructMemberOffsetDecoration>(0, Source{})})});
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
@@ -1218,8 +1196,7 @@
   ast::type::Vector ivec3(&i32, 3);
   ast::type::Vector fvec3(&f32, 3);
 
-  auto* data_str = create<ast::Struct>();
-  data_str->set_members({
+  auto* data_str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &ivec3,
           ast::StructMemberDecorationList{
@@ -1235,11 +1212,11 @@
   ast::type::Array ary(&data, 4);
   ary.set_decorations({create<ast::StrideDecoration>(32, Source{})});
 
-  auto* pre_str = create<ast::Struct>();
-  pre_str->set_members({create<ast::StructMember>(
-      "c", &ary,
-      ast::StructMemberDecorationList{
-          create<ast::StructMemberOffsetDecoration>(0, Source{})})});
+  auto* pre_str =
+      create<ast::Struct>(ast::StructMemberList{create<ast::StructMember>(
+          "c", &ary,
+          ast::StructMemberDecorationList{
+              create<ast::StructMemberOffsetDecoration>(0, Source{})})});
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index e8fcb64..b2156f7 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -181,8 +181,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -206,8 +205,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -231,8 +229,7 @@
   decos.push_back(create<ast::StructMemberOffsetDecoration>(128, Source{}));
   members.push_back(create<ast::StructMember>("c", &f32, decos));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -258,8 +255,7 @@
   ast::StructMemberDecorationList b_deco;
   members.push_back(create<ast::StructMember>("float", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
diff --git a/src/writer/msl/generator_impl_alias_type_test.cc b/src/writer/msl/generator_impl_alias_type_test.cc
index ac4b895..d2b4e84 100644
--- a/src/writer/msl/generator_impl_alias_type_test.cc
+++ b/src/writer/msl/generator_impl_alias_type_test.cc
@@ -61,8 +61,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &i32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("a", str);
 
@@ -86,8 +85,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &i32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("b", str);
   ast::type::Alias alias("a", &s);
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index 51697e9..1f9d0e9 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -295,8 +295,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
@@ -363,8 +362,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadOnly, &s);
@@ -731,8 +729,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
@@ -818,8 +815,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadOnly, &s);
diff --git a/src/writer/msl/generator_impl_test.cc b/src/writer/msl/generator_impl_test.cc
index 15f488a..b366f44 100644
--- a/src/writer/msl/generator_impl_test.cc
+++ b/src/writer/msl/generator_impl_test.cc
@@ -168,8 +168,7 @@
   decos.push_back(create<ast::StructMemberOffsetDecoration>(128, Source{}));
   members.push_back(create<ast::StructMember>("c", &f32, decos));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -193,8 +192,7 @@
   decos.push_back(create<ast::StructMemberOffsetDecoration>(32, Source{}));
   members.push_back(create<ast::StructMember>("c", &f32, decos));
 
-  auto* inner_str = create<ast::Struct>();
-  inner_str->set_members(members);
+  auto* inner_str = create<ast::Struct>(members);
 
   ast::type::Struct inner_s("Inner", inner_str);
 
@@ -207,8 +205,7 @@
   decos.push_back(create<ast::StructMemberOffsetDecoration>(64, Source{}));
   members.push_back(create<ast::StructMember>("f", &f32, decos));
 
-  auto* outer_str = create<ast::Struct>();
-  outer_str->set_members(members);
+  auto* outer_str = create<ast::Struct>(members);
 
   ast::type::Struct outer_s("Outer", outer_str);
 
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index 02340e9..e3a58ee 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -183,8 +183,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -204,8 +203,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -221,8 +219,7 @@
   ast::type::I32 i32;
   ast::type::F32 f32;
 
-  auto* str = create<ast::Struct>();
-  str->set_members({
+  auto* str = create<ast::Struct>(ast::StructMemberList{
       create<ast::StructMember>(
           "a", &i32,
           ast::StructMemberDecorationList{
@@ -262,8 +259,7 @@
   ast::StructMemberDecorationList b_deco;
   members.push_back(create<ast::StructMember>("float", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
diff --git a/src/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
index 315dfa5..03a20b5 100644
--- a/src/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -90,8 +90,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index f1c98d4..219fbe1 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -279,7 +279,7 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_Empty) {
-  auto* s = create<ast::Struct>();
+  auto* s = create<ast::Struct>(ast::StructMemberList{});
   ast::type::Struct s_type("S", s);
 
   auto id = b.GenerateTypeIfNeeded(&s_type);
diff --git a/src/writer/wgsl/generator_impl_alias_type_test.cc b/src/writer/wgsl/generator_impl_alias_type_test.cc
index 693c75d..c2ac83d 100644
--- a/src/writer/wgsl/generator_impl_alias_type_test.cc
+++ b/src/writer/wgsl/generator_impl_alias_type_test.cc
@@ -51,8 +51,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &i32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("A", str);
   ast::type::Alias alias("B", &s);
@@ -80,8 +79,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &i32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("A", str);
   ast::type::Alias alias("B", &s);
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc
index 202e8fc..7693db2 100644
--- a/src/writer/wgsl/generator_impl_type_test.cc
+++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -185,8 +185,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);
 
@@ -206,8 +205,7 @@
   b_deco.push_back(create<ast::StructMemberOffsetDecoration>(4, Source{}));
   members.push_back(create<ast::StructMember>("b", &f32, b_deco));
 
-  auto* str = create<ast::Struct>();
-  str->set_members(members);
+  auto* str = create<ast::Struct>(members);
 
   ast::type::Struct s("S", str);