ast: Merge DecoratedVariable into Variable

Remove all Variable setters (with exception to set_storage_class() which is called by the TypeDeterminer)

Bug: tint:390
Change-Id: I172667e21e2b02e85dcea6703aa1e608ec718250
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/35015
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 32f7177..61f5862 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -259,8 +259,6 @@
     "src/ast/constructor_expression.h",
     "src/ast/continue_statement.cc",
     "src/ast/continue_statement.h",
-    "src/ast/decorated_variable.cc",
-    "src/ast/decorated_variable.h",
     "src/ast/decoration.cc",
     "src/ast/decoration.h",
     "src/ast/discard_statement.cc",
@@ -765,7 +763,6 @@
     "src/ast/clone_context_test.cc",
     "src/ast/constant_id_decoration_test.cc",
     "src/ast/continue_statement_test.cc",
-    "src/ast/decorated_variable_test.cc",
     "src/ast/decoration_test.cc",
     "src/ast/discard_statement_test.cc",
     "src/ast/else_statement_test.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index cd7797e..a80cd1a 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -80,8 +80,6 @@
   ast/constructor_expression.h
   ast/continue_statement.cc
   ast/continue_statement.h
-  ast/decorated_variable.cc
-  ast/decorated_variable.h
   ast/decoration.cc
   ast/decoration.h
   ast/discard_statement.cc
@@ -403,7 +401,6 @@
     ast/continue_statement_test.cc
     ast/discard_statement_test.cc
     ast/decoration_test.cc
-    ast/decorated_variable_test.cc
     ast/else_statement_test.cc
     ast/expression_test.cc
     ast/fallthrough_statement_test.cc
diff --git a/src/ast/builder.cc b/src/ast/builder.cc
index 6045083..2c7479c 100644
--- a/src/ast/builder.cc
+++ b/src/ast/builder.cc
@@ -32,7 +32,16 @@
 Variable* Builder::Var(const std::string& name,
                        StorageClass storage,
                        type::Type* type) {
-  auto* var = create<Variable>(Source{}, name, storage, type);
+  return Var(name, storage, type, nullptr, {});
+}
+
+Variable* Builder::Var(const std::string& name,
+                       StorageClass storage,
+                       type::Type* type,
+                       Expression* constructor,
+                       VariableDecorationList decorations) {
+  auto* var = create<Variable>(Source{}, name, storage, type, false,
+                               constructor, decorations);
   OnVariableBuilt(var);
   return var;
 }
@@ -40,8 +49,16 @@
 Variable* Builder::Const(const std::string& name,
                          StorageClass storage,
                          type::Type* type) {
-  auto* var = create<Variable>(Source{}, name, storage, type);
-  var->set_is_const(true);
+  return Const(name, storage, type, nullptr, {});
+}
+
+Variable* Builder::Const(const std::string& name,
+                         StorageClass storage,
+                         type::Type* type,
+                         Expression* constructor,
+                         VariableDecorationList decorations) {
+  auto* var = create<Variable>(Source{}, name, storage, type, true, constructor,
+                               decorations);
   OnVariableBuilt(var);
   return var;
 }
diff --git a/src/ast/builder.h b/src/ast/builder.h
index 59d3ce2..4a01d50 100644
--- a/src/ast/builder.h
+++ b/src/ast/builder.h
@@ -428,7 +428,8 @@
   /// @param name the variable name
   /// @param storage the variable storage class
   /// @param type the variable type
-  /// @returns a `Variable` with the given name, storage and type
+  /// @returns a `Variable` with the given name, storage and type. The variable
+  /// will be built with a nullptr constructor and no decorations.
   Variable* Var(const std::string& name,
                 StorageClass storage,
                 type::Type* type);
@@ -436,11 +437,36 @@
   /// @param name the variable name
   /// @param storage the variable storage class
   /// @param type the variable type
-  /// @returns a constant `Variable` with the given name, storage and type
+  /// @param constructor constructor expression
+  /// @param decorations variable decorations
+  /// @returns a `Variable` with the given name, storage and type
+  Variable* Var(const std::string& name,
+                StorageClass storage,
+                type::Type* type,
+                Expression* constructor,
+                VariableDecorationList decorations);
+
+  /// @param name the variable name
+  /// @param storage the variable storage class
+  /// @param type the variable type
+  /// @returns a constant `Variable` with the given name, storage and type. The
+  /// variable will be built with a nullptr constructor and no decorations.
   Variable* Const(const std::string& name,
                   StorageClass storage,
                   type::Type* type);
 
+  /// @param name the variable name
+  /// @param storage the variable storage class
+  /// @param type the variable type
+  /// @param constructor optional constructor expression
+  /// @param decorations optional variable decorations
+  /// @returns a constant `Variable` with the given name, storage and type
+  Variable* Const(const std::string& name,
+                  StorageClass storage,
+                  type::Type* type,
+                  Expression* constructor,
+                  VariableDecorationList decorations);
+
   /// @param func the function name
   /// @param args the function call arguments
   /// @returns a `CallExpression` to the function `func`, with the
diff --git a/src/ast/decorated_variable.cc b/src/ast/decorated_variable.cc
deleted file mode 100644
index e8e4874..0000000
--- a/src/ast/decorated_variable.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/ast/decorated_variable.h"
-
-#include <cassert>
-
-#include "src/ast/builtin_decoration.h"
-#include "src/ast/clone_context.h"
-#include "src/ast/constant_id_decoration.h"
-#include "src/ast/location_decoration.h"
-#include "src/ast/module.h"
-
-TINT_INSTANTIATE_CLASS_ID(tint::ast::DecoratedVariable);
-
-namespace tint {
-namespace ast {
-
-DecoratedVariable::DecoratedVariable() = default;
-
-DecoratedVariable::DecoratedVariable(Variable* var)
-    : Base(var->source(), var->name(), var->storage_class(), var->type()) {}
-
-DecoratedVariable::DecoratedVariable(DecoratedVariable&&) = default;
-
-DecoratedVariable::~DecoratedVariable() = default;
-
-bool DecoratedVariable::HasLocationDecoration() const {
-  for (auto* deco : decorations_) {
-    if (deco->Is<LocationDecoration>()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool DecoratedVariable::HasBuiltinDecoration() const {
-  for (auto* deco : decorations_) {
-    if (deco->Is<BuiltinDecoration>()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool DecoratedVariable::HasConstantIdDecoration() const {
-  for (auto* deco : decorations_) {
-    if (deco->Is<ConstantIdDecoration>()) {
-      return true;
-    }
-  }
-  return false;
-}
-
-uint32_t DecoratedVariable::constant_id() const {
-  assert(HasConstantIdDecoration());
-  for (auto* deco : decorations_) {
-    if (auto* cid = deco->As<ConstantIdDecoration>()) {
-      return cid->value();
-    }
-  }
-  return 0;
-}
-
-DecoratedVariable* DecoratedVariable::Clone(CloneContext* ctx) const {
-  auto* cloned = ctx->mod->create<DecoratedVariable>();
-  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());
-  cloned->set_decorations(ctx->Clone(decorations()));
-  return cloned;
-}
-
-bool DecoratedVariable::IsValid() const {
-  return Variable::IsValid();
-}
-
-void DecoratedVariable::to_str(std::ostream& out, size_t indent) const {
-  make_indent(out, indent);
-  out << "DecoratedVariable";
-  if (is_const()) {
-    out << "Const";
-  }
-  out << "{" << std::endl;
-
-  make_indent(out, indent + 2);
-  out << "Decorations{" << std::endl;
-  for (auto* deco : decorations_) {
-    deco->to_str(out, indent + 4);
-  }
-
-  make_indent(out, indent + 2);
-  out << "}" << std::endl;
-
-  info_to_str(out, indent + 2);
-  constructor_to_str(out, indent + 2);
-  make_indent(out, indent);
-  out << "}" << std::endl;
-}
-
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/decorated_variable.h b/src/ast/decorated_variable.h
deleted file mode 100644
index 2e0aeee..0000000
--- a/src/ast/decorated_variable.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_AST_DECORATED_VARIABLE_H_
-#define SRC_AST_DECORATED_VARIABLE_H_
-
-#include <memory>
-#include <utility>
-
-#include "src/ast/variable.h"
-#include "src/ast/variable_decoration.h"
-
-namespace tint {
-namespace ast {
-
-/// A Decorated Variable statement.
-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
-  explicit DecoratedVariable(Variable* var);
-  /// Move constructor
-  DecoratedVariable(DecoratedVariable&&);
-
-  ~DecoratedVariable() override;
-
-  /// Sets a decoration to the variable
-  /// @param decos the decorations to set
-  void set_decorations(VariableDecorationList decos) {
-    decorations_ = std::move(decos);
-  }
-  /// @returns the decorations attached to this variable
-  const VariableDecorationList& decorations() const { return decorations_; }
-
-  /// @returns true if the decorations include a LocationDecoration
-  bool HasLocationDecoration() const;
-  /// @returns true if the deocrations include a BuiltinDecoration
-  bool HasBuiltinDecoration() const;
-  /// @returns true if the decorations include a ConstantIdDecoration
-  bool HasConstantIdDecoration() const;
-
-  /// @returns the constant_id value for the variable. Assumes that
-  /// HasConstantIdDecoration() has been called first.
-  uint32_t constant_id() const;
-
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @note Semantic information such as resolved expression type and intrinsic
-  /// information is not cloned.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  DecoratedVariable* Clone(CloneContext* ctx) const override;
-
-  /// @returns true if the name and path are both present
-  bool IsValid() const override;
-
-  /// @param out the stream to write to
-  /// @param indent number of spaces to indent the node when writing
-  void to_str(std::ostream& out, size_t indent) const override;
-
- private:
-  DecoratedVariable(const DecoratedVariable&) = delete;
-
-  VariableDecorationList decorations_;
-};
-
-}  // namespace ast
-}  // namespace tint
-
-#endif  // SRC_AST_DECORATED_VARIABLE_H_
diff --git a/src/ast/decorated_variable_test.cc b/src/ast/decorated_variable_test.cc
deleted file mode 100644
index 31ac563..0000000
--- a/src/ast/decorated_variable_test.cc
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/ast/decorated_variable.h"
-
-#include "src/ast/binding_decoration.h"
-#include "src/ast/builtin_decoration.h"
-#include "src/ast/constant_id_decoration.h"
-#include "src/ast/identifier_expression.h"
-#include "src/ast/location_decoration.h"
-#include "src/ast/set_decoration.h"
-#include "src/ast/test_helper.h"
-#include "src/ast/type/f32_type.h"
-#include "src/ast/type/i32_type.h"
-#include "src/ast/variable.h"
-#include "src/ast/variable_decoration.h"
-
-namespace tint {
-namespace ast {
-namespace {
-
-using DecoratedVariableTest = TestHelper;
-
-TEST_F(DecoratedVariableTest, Creation) {
-  type::I32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t);
-  DecoratedVariable dv(var);
-
-  EXPECT_EQ(dv.name(), "my_var");
-  EXPECT_EQ(dv.storage_class(), StorageClass::kFunction);
-  EXPECT_EQ(dv.type(), &t);
-  EXPECT_EQ(dv.source().range.begin.line, 0u);
-  EXPECT_EQ(dv.source().range.begin.column, 0u);
-  EXPECT_EQ(dv.source().range.end.line, 0u);
-  EXPECT_EQ(dv.source().range.end.column, 0u);
-}
-
-TEST_F(DecoratedVariableTest, CreationWithSource) {
-  Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}};
-  type::F32 t;
-  auto* var = create<Variable>(s, "i", StorageClass::kPrivate, &t);
-  DecoratedVariable dv(var);
-
-  EXPECT_EQ(dv.name(), "i");
-  EXPECT_EQ(dv.storage_class(), StorageClass::kPrivate);
-  EXPECT_EQ(dv.type(), &t);
-  EXPECT_EQ(dv.source().range.begin.line, 27u);
-  EXPECT_EQ(dv.source().range.begin.column, 4u);
-  EXPECT_EQ(dv.source().range.end.line, 27u);
-  EXPECT_EQ(dv.source().range.end.column, 5u);
-}
-
-TEST_F(DecoratedVariableTest, NoDecorations) {
-  type::I32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t);
-  DecoratedVariable dv(var);
-  EXPECT_FALSE(dv.HasLocationDecoration());
-  EXPECT_FALSE(dv.HasBuiltinDecoration());
-  EXPECT_FALSE(dv.HasConstantIdDecoration());
-}
-
-TEST_F(DecoratedVariableTest, WithDecorations) {
-  type::F32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t);
-  DecoratedVariable dv(var);
-
-  VariableDecorationList decos;
-  decos.push_back(create<LocationDecoration>(1, Source{}));
-  decos.push_back(create<BuiltinDecoration>(Builtin::kPosition, Source{}));
-  decos.push_back(create<ConstantIdDecoration>(1200, Source{}));
-
-  dv.set_decorations(decos);
-
-  EXPECT_TRUE(dv.HasLocationDecoration());
-  EXPECT_TRUE(dv.HasBuiltinDecoration());
-  EXPECT_TRUE(dv.HasConstantIdDecoration());
-}
-
-TEST_F(DecoratedVariableTest, ConstantId) {
-  type::F32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t);
-  DecoratedVariable dv(var);
-
-  VariableDecorationList decos;
-  decos.push_back(create<ConstantIdDecoration>(1200, Source{}));
-  dv.set_decorations(decos);
-
-  EXPECT_EQ(dv.constant_id(), 1200u);
-}
-
-TEST_F(DecoratedVariableTest, IsValid) {
-  type::I32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kNone, &t);
-  DecoratedVariable dv(var);
-  EXPECT_TRUE(dv.IsValid());
-}
-
-TEST_F(DecoratedVariableTest, IsDecorated) {
-  type::I32 t;
-  DecoratedVariable dv(
-      create<Variable>(Source{}, "my_var", StorageClass::kNone, &t));
-  EXPECT_TRUE(dv.Is<DecoratedVariable>());
-}
-
-TEST_F(DecoratedVariableTest, to_str) {
-  type::F32 t;
-  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t);
-  DecoratedVariable dv(var);
-  dv.set_constructor(create<IdentifierExpression>("expr"));
-
-  VariableDecorationList decos;
-  decos.push_back(create<BindingDecoration>(2, Source{}));
-  decos.push_back(create<SetDecoration>(1, Source{}));
-
-  dv.set_decorations(decos);
-  std::ostringstream out;
-  dv.to_str(out, 2);
-  EXPECT_EQ(out.str(), R"(  DecoratedVariable{
-    Decorations{
-      BindingDecoration{2}
-      SetDecoration{1}
-    }
-    my_var
-    function
-    __f32
-    {
-      Identifier[not set]{expr}
-    }
-  }
-)");
-}
-
-}  // namespace
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/function.cc b/src/ast/function.cc
index 5dce7e0..26522e8 100644
--- a/src/ast/function.cc
+++ b/src/ast/function.cc
@@ -17,12 +17,12 @@
 #include <sstream>
 
 #include "src/ast/clone_context.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/module.h"
 #include "src/ast/stage_decoration.h"
 #include "src/ast/type/multisampled_texture_type.h"
 #include "src/ast/type/sampled_texture_type.h"
 #include "src/ast/type/texture_type.h"
+#include "src/ast/variable.h"
 #include "src/ast/workgroup_decoration.h"
 
 TINT_INSTANTIATE_CLASS_ID(tint::ast::Function);
@@ -88,12 +88,10 @@
   std::vector<std::pair<Variable*, LocationDecoration*>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (auto* decos = var->As<DecoratedVariable>()) {
-      for (auto* deco : decos->decorations()) {
-        if (auto* location = deco->As<LocationDecoration>()) {
-          ret.push_back({var, location});
-          break;
-        }
+    for (auto* deco : var->decorations()) {
+      if (auto* location = deco->As<LocationDecoration>()) {
+        ret.push_back({var, location});
+        break;
       }
     }
   }
@@ -109,22 +107,20 @@
       continue;
     }
 
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      BindingDecoration* binding = nullptr;
-      SetDecoration* set = nullptr;
-      for (auto* deco : decorated->decorations()) {
-        if (auto* b = deco->As<BindingDecoration>()) {
-          binding = b;
-        } else if (auto* s = deco->As<SetDecoration>()) {
-          set = s;
-        }
+    BindingDecoration* binding = nullptr;
+    SetDecoration* set = nullptr;
+    for (auto* deco : var->decorations()) {
+      if (auto* b = deco->As<BindingDecoration>()) {
+        binding = b;
+      } else if (auto* s = deco->As<SetDecoration>()) {
+        set = s;
       }
-      if (binding == nullptr || set == nullptr) {
-        continue;
-      }
-
-      ret.push_back({var, BindingInfo{binding, set}});
     }
+    if (binding == nullptr || set == nullptr) {
+      continue;
+    }
+
+    ret.push_back({var, BindingInfo{binding, set}});
   }
   return ret;
 }
@@ -138,22 +134,20 @@
       continue;
     }
 
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      BindingDecoration* binding = nullptr;
-      SetDecoration* set = nullptr;
-      for (auto* deco : decorated->decorations()) {
-        if (auto* b = deco->As<BindingDecoration>()) {
-          binding = b;
-        } else if (auto* s = deco->As<SetDecoration>()) {
-          set = s;
-        }
+    BindingDecoration* binding = nullptr;
+    SetDecoration* set = nullptr;
+    for (auto* deco : var->decorations()) {
+      if (auto* b = deco->As<BindingDecoration>()) {
+        binding = b;
+      } else if (auto* s = deco->As<SetDecoration>()) {
+        set = s;
       }
-      if (binding == nullptr || set == nullptr) {
-        continue;
-      }
-
-      ret.push_back({var, BindingInfo{binding, set}});
     }
+    if (binding == nullptr || set == nullptr) {
+      continue;
+    }
+
+    ret.push_back({var, BindingInfo{binding, set}});
   }
   return ret;
 }
@@ -163,12 +157,10 @@
   std::vector<std::pair<Variable*, BuiltinDecoration*>> ret;
 
   for (auto* var : referenced_module_variables()) {
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      for (auto* deco : decorated->decorations()) {
-        if (auto* builtin = deco->As<BuiltinDecoration>()) {
-          ret.push_back({var, builtin});
-          break;
-        }
+    for (auto* deco : var->decorations()) {
+      if (auto* builtin = deco->As<BuiltinDecoration>()) {
+        ret.push_back({var, builtin});
+        break;
       }
     }
   }
@@ -200,12 +192,10 @@
   std::vector<std::pair<Variable*, BuiltinDecoration*>> ret;
 
   for (auto* var : local_referenced_module_variables()) {
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      for (auto* deco : decorated->decorations()) {
-        if (auto* builtin = deco->As<BuiltinDecoration>()) {
-          ret.push_back({var, builtin});
-          break;
-        }
+    for (auto* deco : var->decorations()) {
+      if (auto* builtin = deco->As<BuiltinDecoration>()) {
+        ret.push_back({var, builtin});
+        break;
       }
     }
   }
@@ -314,23 +304,21 @@
       continue;
     }
 
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      BindingDecoration* binding = nullptr;
-      SetDecoration* set = nullptr;
-      for (auto* deco : decorated->decorations()) {
-        if (auto* b = deco->As<BindingDecoration>()) {
-          binding = b;
-        }
-        if (auto* s = deco->As<SetDecoration>()) {
-          set = s;
-        }
+    BindingDecoration* binding = nullptr;
+    SetDecoration* set = nullptr;
+    for (auto* deco : var->decorations()) {
+      if (auto* b = deco->As<BindingDecoration>()) {
+        binding = b;
       }
-      if (binding == nullptr || set == nullptr) {
-        continue;
+      if (auto* s = deco->As<SetDecoration>()) {
+        set = s;
       }
-
-      ret.push_back({var, BindingInfo{binding, set}});
     }
+    if (binding == nullptr || set == nullptr) {
+      continue;
+    }
+
+    ret.push_back({var, BindingInfo{binding, set}});
   }
   return ret;
 }
@@ -353,22 +341,20 @@
       continue;
     }
 
-    if (auto* decorated = var->As<DecoratedVariable>()) {
-      BindingDecoration* binding = nullptr;
-      SetDecoration* set = nullptr;
-      for (auto* deco : decorated->decorations()) {
-        if (auto* b = deco->As<BindingDecoration>()) {
-          binding = b;
-        } else if (auto* s = deco->As<SetDecoration>()) {
-          set = s;
-        }
+    BindingDecoration* binding = nullptr;
+    SetDecoration* set = nullptr;
+    for (auto* deco : var->decorations()) {
+      if (auto* b = deco->As<BindingDecoration>()) {
+        binding = b;
+      } else if (auto* s = deco->As<SetDecoration>()) {
+        set = s;
       }
-      if (binding == nullptr || set == nullptr) {
-        continue;
-      }
-
-      ret.push_back({var, BindingInfo{binding, set}});
     }
+    if (binding == nullptr || set == nullptr) {
+      continue;
+    }
+
+    ret.push_back({var, BindingInfo{binding, set}});
   }
 
   return ret;
diff --git a/src/ast/function_test.cc b/src/ast/function_test.cc
index 1413792..68f9921 100644
--- a/src/ast/function_test.cc
+++ b/src/ast/function_test.cc
@@ -15,7 +15,6 @@
 #include "src/ast/function.h"
 
 #include "src/ast/builtin_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/pipeline_stage.h"
@@ -37,8 +36,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
   auto* var = params[0];
 
   Function f(Source{}, "func", params, &void_type, create<BlockStatement>(),
@@ -54,8 +54,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   Function f(Source{Source::Location{20, 2}}, "func", params, &void_type,
              create<BlockStatement>(), FunctionDecorationList{});
@@ -68,7 +69,8 @@
   type::Void void_type;
   type::I32 i32;
 
-  Variable v(Source{}, "var", StorageClass::kInput, &i32);
+  Variable v(Source{}, "var", StorageClass::kInput, &i32, false, nullptr,
+             ast::VariableDecorationList{});
   Function f(Source{}, "func", VariableList{}, &void_type,
              create<BlockStatement>(), FunctionDecorationList{});
 
@@ -79,7 +81,8 @@
   f.add_referenced_module_variable(&v);
   ASSERT_EQ(f.referenced_module_variables().size(), 1u);
 
-  Variable v2(Source{}, "var2", StorageClass::kOutput, &i32);
+  Variable v2(Source{}, "var2", StorageClass::kOutput, &i32, false, nullptr,
+              ast::VariableDecorationList{});
   f.add_referenced_module_variable(&v2);
   ASSERT_EQ(f.referenced_module_variables().size(), 2u);
   EXPECT_EQ(f.referenced_module_variables()[1], &v2);
@@ -89,38 +92,44 @@
   type::Void void_type;
   type::I32 i32;
 
-  DecoratedVariable loc1(
-      create<Variable>(Source{}, "loc1", StorageClass::kInput, &i32));
-  loc1.set_decorations({create<LocationDecoration>(0, Source{})});
+  auto* loc1 = create<Variable>(Source{}, "loc1", StorageClass::kInput, &i32,
+                                false, nullptr,
+                                ast::VariableDecorationList{
+                                    create<LocationDecoration>(0, Source{}),
+                                });
 
-  DecoratedVariable loc2(
-      create<Variable>(Source{}, "loc2", StorageClass::kInput, &i32));
-  loc2.set_decorations({create<LocationDecoration>(1, Source{})});
+  auto* loc2 = create<Variable>(Source{}, "loc2", StorageClass::kInput, &i32,
+                                false, nullptr,
+                                ast::VariableDecorationList{
+                                    create<LocationDecoration>(1, Source{}),
+                                });
 
-  DecoratedVariable builtin1(
-      create<Variable>(Source{}, "builtin1", StorageClass::kInput, &i32));
-  builtin1.set_decorations(
-      {create<BuiltinDecoration>(Builtin::kPosition, Source{})});
+  auto* builtin1 = create<Variable>(
+      Source{}, "builtin1", StorageClass::kInput, &i32, false, nullptr,
+      ast::VariableDecorationList{
+          create<BuiltinDecoration>(Builtin::kPosition, Source{}),
+      });
 
-  DecoratedVariable builtin2(
-      create<Variable>(Source{}, "builtin2", StorageClass::kInput, &i32));
-  builtin2.set_decorations(
-      {create<BuiltinDecoration>(Builtin::kFragDepth, Source{})});
+  auto* builtin2 = create<Variable>(
+      Source{}, "builtin2", StorageClass::kInput, &i32, false, nullptr,
+      ast::VariableDecorationList{
+          create<BuiltinDecoration>(Builtin::kFragDepth, Source{}),
+      });
 
   Function f(Source{}, "func", VariableList{}, &void_type,
              create<BlockStatement>(), FunctionDecorationList{});
 
-  f.add_referenced_module_variable(&loc1);
-  f.add_referenced_module_variable(&builtin1);
-  f.add_referenced_module_variable(&loc2);
-  f.add_referenced_module_variable(&builtin2);
+  f.add_referenced_module_variable(loc1);
+  f.add_referenced_module_variable(builtin1);
+  f.add_referenced_module_variable(loc2);
+  f.add_referenced_module_variable(builtin2);
   ASSERT_EQ(f.referenced_module_variables().size(), 4u);
 
   auto ref_locs = f.referenced_location_variables();
   ASSERT_EQ(ref_locs.size(), 2u);
-  EXPECT_EQ(ref_locs[0].first, &loc1);
+  EXPECT_EQ(ref_locs[0].first, loc1);
   EXPECT_EQ(ref_locs[0].second->value(), 0u);
-  EXPECT_EQ(ref_locs[1].first, &loc2);
+  EXPECT_EQ(ref_locs[1].first, loc2);
   EXPECT_EQ(ref_locs[1].second->value(), 1u);
 }
 
@@ -128,38 +137,44 @@
   type::Void void_type;
   type::I32 i32;
 
-  DecoratedVariable loc1(
-      create<Variable>(Source{}, "loc1", StorageClass::kInput, &i32));
-  loc1.set_decorations({create<LocationDecoration>(0, Source{})});
+  auto* loc1 = create<Variable>(Source{}, "loc1", StorageClass::kInput, &i32,
+                                false, nullptr,
+                                ast::VariableDecorationList{
+                                    create<LocationDecoration>(0, Source{}),
+                                });
 
-  DecoratedVariable loc2(
-      create<Variable>(Source{}, "loc2", StorageClass::kInput, &i32));
-  loc2.set_decorations({create<LocationDecoration>(1, Source{})});
+  auto* loc2 = create<Variable>(Source{}, "loc2", StorageClass::kInput, &i32,
+                                false, nullptr,
+                                ast::VariableDecorationList{
+                                    create<LocationDecoration>(1, Source{}),
+                                });
 
-  DecoratedVariable builtin1(
-      create<Variable>(Source{}, "builtin1", StorageClass::kInput, &i32));
-  builtin1.set_decorations(
-      {create<BuiltinDecoration>(Builtin::kPosition, Source{})});
+  auto* builtin1 = create<Variable>(
+      Source{}, "builtin1", StorageClass::kInput, &i32, false, nullptr,
+      ast::VariableDecorationList{
+          create<BuiltinDecoration>(Builtin::kPosition, Source{}),
+      });
 
-  DecoratedVariable builtin2(
-      create<Variable>(Source{}, "builtin2", StorageClass::kInput, &i32));
-  builtin2.set_decorations(
-      {create<BuiltinDecoration>(Builtin::kFragDepth, Source{})});
+  auto* builtin2 = create<Variable>(
+      Source{}, "builtin2", StorageClass::kInput, &i32, false, nullptr,
+      ast::VariableDecorationList{
+          create<BuiltinDecoration>(Builtin::kFragDepth, Source{}),
+      });
 
   Function f(Source{}, "func", VariableList{}, &void_type,
              create<BlockStatement>(), FunctionDecorationList{});
 
-  f.add_referenced_module_variable(&loc1);
-  f.add_referenced_module_variable(&builtin1);
-  f.add_referenced_module_variable(&loc2);
-  f.add_referenced_module_variable(&builtin2);
+  f.add_referenced_module_variable(loc1);
+  f.add_referenced_module_variable(builtin1);
+  f.add_referenced_module_variable(loc2);
+  f.add_referenced_module_variable(builtin2);
   ASSERT_EQ(f.referenced_module_variables().size(), 4u);
 
   auto ref_locs = f.referenced_builtin_variables();
   ASSERT_EQ(ref_locs.size(), 2u);
-  EXPECT_EQ(ref_locs[0].first, &builtin1);
+  EXPECT_EQ(ref_locs[0].first, builtin1);
   EXPECT_EQ(ref_locs[0].second->value(), Builtin::kPosition);
-  EXPECT_EQ(ref_locs[1].first, &builtin2);
+  EXPECT_EQ(ref_locs[1].first, builtin2);
   EXPECT_EQ(ref_locs[1].second->value(), Builtin::kFragDepth);
 }
 
@@ -182,8 +197,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   auto* body = create<BlockStatement>();
   body->append(create<DiscardStatement>());
@@ -198,8 +214,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   Function f(Source{}, "", params, &void_type, create<BlockStatement>(),
              FunctionDecorationList{});
@@ -210,8 +227,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   Function f(Source{}, "func", params, nullptr, create<BlockStatement>(),
              FunctionDecorationList{});
@@ -223,8 +241,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
   params.push_back(nullptr);
 
   Function f(Source{}, "func", params, &void_type, create<BlockStatement>(),
@@ -236,8 +255,9 @@
   type::Void void_type;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, nullptr));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone,
+                                    nullptr, false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   Function f(Source{}, "func", params, &void_type, create<BlockStatement>(),
              FunctionDecorationList{});
@@ -249,8 +269,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   auto* body = create<BlockStatement>();
   body->append(create<DiscardStatement>());
@@ -267,8 +288,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   auto* body = create<BlockStatement>();
   body->append(create<DiscardStatement>());
@@ -325,8 +347,9 @@
   type::I32 i32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var", StorageClass::kNone, &i32));
+  params.push_back(create<Variable>(Source{}, "var", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   auto* body = create<BlockStatement>();
   body->append(create<DiscardStatement>());
@@ -364,10 +387,12 @@
   type::F32 f32;
 
   VariableList params;
-  params.push_back(
-      create<Variable>(Source{}, "var1", StorageClass::kNone, &i32));
-  params.push_back(
-      create<Variable>(Source{}, "var2", StorageClass::kNone, &f32));
+  params.push_back(create<Variable>(Source{}, "var1", StorageClass::kNone, &i32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
+  params.push_back(create<Variable>(Source{}, "var2", StorageClass::kNone, &f32,
+                                    false, nullptr,
+                                    ast::VariableDecorationList{}));
 
   Function f(Source{}, "func", params, &void_type, create<BlockStatement>(),
              FunctionDecorationList{});
diff --git a/src/ast/module_test.cc b/src/ast/module_test.cc
index 6a1978a..3303235 100644
--- a/src/ast/module_test.cc
+++ b/src/ast/module_test.cc
@@ -67,7 +67,8 @@
 
 TEST_F(ModuleTest, IsValid_GlobalVariable) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "var", StorageClass::kInput, &f32);
+  auto* var = create<Variable>(Source{}, "var", StorageClass::kInput, &f32,
+                               false, nullptr, ast::VariableDecorationList{});
 
   Module m;
   m.AddGlobalVariable(var);
@@ -81,7 +82,8 @@
 }
 
 TEST_F(ModuleTest, IsValid_Invalid_GlobalVariable) {
-  auto* var = create<Variable>(Source{}, "var", StorageClass::kInput, nullptr);
+  auto* var = create<Variable>(Source{}, "var", StorageClass::kInput, nullptr,
+                               false, nullptr, ast::VariableDecorationList{});
 
   Module m;
   m.AddGlobalVariable(var);
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index d97253e..e31b02e 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -17,7 +17,7 @@
 #include <assert.h>
 
 #include "src/ast/clone_context.h"
-#include "src/ast/decorated_variable.h"
+#include "src/ast/constant_id_decoration.h"
 #include "src/ast/module.h"
 
 TINT_INSTANTIATE_CLASS_ID(tint::ast::Variable);
@@ -25,24 +25,66 @@
 namespace tint {
 namespace ast {
 
-Variable::Variable() = default;
-
 Variable::Variable(const Source& source,
                    const std::string& name,
                    StorageClass sc,
-                   type::Type* type)
-    : Base(source), name_(name), storage_class_(sc), type_(type) {}
+                   type::Type* type,
+                   bool is_const,
+                   Expression* constructor,
+                   VariableDecorationList decorations)
+    : Base(source),
+      name_(name),
+      storage_class_(sc),
+      type_(type),
+      is_const_(is_const),
+      constructor_(constructor),
+      decorations_(std::move(decorations)) {}
 
 Variable::Variable(Variable&&) = default;
 
 Variable::~Variable() = default;
 
+bool Variable::HasLocationDecoration() const {
+  for (auto* deco : decorations_) {
+    if (deco->Is<LocationDecoration>()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Variable::HasBuiltinDecoration() const {
+  for (auto* deco : decorations_) {
+    if (deco->Is<BuiltinDecoration>()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+bool Variable::HasConstantIdDecoration() const {
+  for (auto* deco : decorations_) {
+    if (deco->Is<ConstantIdDecoration>()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+uint32_t Variable::constant_id() const {
+  assert(HasConstantIdDecoration());
+  for (auto* deco : decorations_) {
+    if (auto* cid = deco->As<ConstantIdDecoration>()) {
+      return cid->value();
+    }
+  }
+  return 0;
+}
+
 Variable* Variable::Clone(CloneContext* ctx) const {
-  auto* cloned = ctx->mod->create<Variable>(
-      ctx->Clone(source()), name(), storage_class(), ctx->Clone(type()));
-  cloned->set_constructor(ctx->Clone(constructor()));
-  cloned->set_is_const(is_const());
-  return cloned;
+  return ctx->mod->create<Variable>(
+      ctx->Clone(source()), name(), storage_class(), ctx->Clone(type()),
+      is_const_, ctx->Clone(constructor()), ctx->Clone(decorations_));
 }
 
 bool Variable::IsValid() const {
@@ -87,6 +129,17 @@
     out << "Const";
   }
   out << "{" << std::endl;
+
+  if (!decorations_.empty()) {
+    make_indent(out, indent + 2);
+    out << "Decorations{" << std::endl;
+    for (auto* deco : decorations_) {
+      deco->to_str(out, indent + 4);
+    }
+    make_indent(out, indent + 2);
+    out << "}" << std::endl;
+  }
+
   info_to_str(out, indent + 2);
   constructor_to_str(out, indent + 2);
   make_indent(out, indent);
diff --git a/src/ast/variable.h b/src/ast/variable.h
index a226bdd..b15d222 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -25,6 +25,7 @@
 #include "src/ast/node.h"
 #include "src/ast/storage_class.h"
 #include "src/ast/type/type.h"
+#include "src/ast/variable_decoration.h"
 
 namespace tint {
 namespace ast {
@@ -83,25 +84,24 @@
   /// @param name the variables name
   /// @param sc the variable storage class
   /// @param type the value type
+  /// @param is_const true if the variable is const
+  /// @param constructor the constructor expression
+  /// @param decorations the variable decorations
   Variable(const Source& source,
            const std::string& name,
            StorageClass sc,
-           type::Type* type);
+           type::Type* type,
+           bool is_const,
+           Expression* constructor,
+           VariableDecorationList decorations);
   /// Move constructor
   Variable(Variable&&);
 
   ~Variable() override;
 
-  /// Sets the variable name
-  /// @param name the name to set
-  void set_name(const std::string& name) { name_ = name; }
   /// @returns the variable name
   const std::string& name() const { return name_; }
 
-  /// Sets the value type if a const or formal parameter, or the
-  /// store type if a var.
-  /// @param type the type
-  void set_type(type::Type* type) { type_ = type; }
   /// @returns the variable's type.
   type::Type* type() const { return type_; }
 
@@ -111,20 +111,28 @@
   /// @returns the storage class
   StorageClass storage_class() const { return storage_class_; }
 
-  /// Sets the constructor
-  /// @param expr the constructor expression
-  void set_constructor(Expression* expr) { constructor_ = expr; }
   /// @returns the constructor expression or nullptr if none set
   Expression* constructor() const { return constructor_; }
   /// @returns true if the variable has an constructor
   bool has_constructor() const { return constructor_ != nullptr; }
 
-  /// Sets if the variable is constant
-  /// @param val the value to be set
-  void set_is_const(bool val) { is_const_ = val; }
   /// @returns true if this is a constant, false otherwise
   bool is_const() const { return is_const_; }
 
+  /// @returns the decorations attached to this variable
+  const VariableDecorationList& decorations() const { return decorations_; }
+
+  /// @returns true if the decorations include a LocationDecoration
+  bool HasLocationDecoration() const;
+  /// @returns true if the deocrations include a BuiltinDecoration
+  bool HasBuiltinDecoration() const;
+  /// @returns true if the decorations include a ConstantIdDecoration
+  bool HasConstantIdDecoration() const;
+
+  /// @returns the constant_id value for the variable. Assumes that
+  /// HasConstantIdDecoration() has been called first.
+  uint32_t constant_id() const;
+
   /// Clones this node and all transitive child nodes using the `CloneContext`
   /// `ctx`.
   /// @note Semantic information such as resolved expression type and intrinsic
@@ -142,10 +150,6 @@
   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
@@ -158,12 +162,13 @@
  private:
   Variable(const Variable&) = delete;
 
-  bool is_const_ = false;
   std::string name_;
   StorageClass storage_class_ = StorageClass::kNone;
   // The value type if a const or formal paramter, and the store type if a var
   type::Type* type_ = nullptr;
+  bool is_const_ = false;
   Expression* constructor_ = nullptr;
+  VariableDecorationList decorations_;
 };
 
 /// A list of variables
diff --git a/src/ast/variable_decl_statement_test.cc b/src/ast/variable_decl_statement_test.cc
index c7e08be..3ef7a4b 100644
--- a/src/ast/variable_decl_statement_test.cc
+++ b/src/ast/variable_decl_statement_test.cc
@@ -26,7 +26,8 @@
 
 TEST_F(VariableDeclStatementTest, Creation) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
 
   VariableDeclStatement stmt(var);
   EXPECT_EQ(stmt.variable(), var);
@@ -34,7 +35,8 @@
 
 TEST_F(VariableDeclStatementTest, Creation_WithSource) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
 
   VariableDeclStatement stmt(Source{Source::Location{20, 2}}, var);
   auto src = stmt.source();
@@ -44,7 +46,8 @@
 
 TEST_F(VariableDeclStatementTest, IsVariableDecl) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
 
   VariableDeclStatement s(var);
   EXPECT_TRUE(s.Is<VariableDeclStatement>());
@@ -52,14 +55,16 @@
 
 TEST_F(VariableDeclStatementTest, IsValid) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
   VariableDeclStatement stmt(var);
   EXPECT_TRUE(stmt.IsValid());
 }
 
 TEST_F(VariableDeclStatementTest, IsValid_InvalidVariable) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
   VariableDeclStatement stmt(var);
   EXPECT_FALSE(stmt.IsValid());
 }
@@ -71,7 +76,8 @@
 
 TEST_F(VariableDeclStatementTest, ToStr) {
   type::F32 f32;
-  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32);
+  auto* var = create<Variable>(Source{}, "a", StorageClass::kNone, &f32, false,
+                               nullptr, ast::VariableDecorationList{});
 
   VariableDeclStatement stmt(Source{Source::Location{20, 2}}, var);
   std::ostringstream out;
diff --git a/src/ast/variable_test.cc b/src/ast/variable_test.cc
index 39dc9f6..5465883 100644
--- a/src/ast/variable_test.cc
+++ b/src/ast/variable_test.cc
@@ -14,6 +14,7 @@
 
 #include "src/ast/variable.h"
 
+#include "src/ast/constant_id_decoration.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/test_helper.h"
 #include "src/ast/type/f32_type.h"
@@ -27,7 +28,8 @@
 
 TEST_F(VariableTest, Creation) {
   type::I32 t;
-  Variable v(Source{}, "my_var", StorageClass::kFunction, &t);
+  Variable v(Source{}, "my_var", StorageClass::kFunction, &t, false, nullptr,
+             ast::VariableDecorationList{});
 
   EXPECT_EQ(v.name(), "my_var");
   EXPECT_EQ(v.storage_class(), StorageClass::kFunction);
@@ -41,7 +43,8 @@
 TEST_F(VariableTest, CreationWithSource) {
   Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}};
   type::F32 t;
-  Variable v(s, "i", StorageClass::kPrivate, &t);
+  Variable v(s, "i", StorageClass::kPrivate, &t, false, nullptr,
+             ast::VariableDecorationList{});
 
   EXPECT_EQ(v.name(), "i");
   EXPECT_EQ(v.storage_class(), StorageClass::kPrivate);
@@ -55,7 +58,8 @@
 TEST_F(VariableTest, CreationEmpty) {
   type::I32 t;
   Source s{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}};
-  Variable v(s, "a_var", StorageClass::kWorkgroup, &t);
+  Variable v(s, "a_var", StorageClass::kWorkgroup, &t, false, nullptr,
+             ast::VariableDecorationList{});
 
   EXPECT_EQ(v.name(), "a_var");
   EXPECT_EQ(v.storage_class(), StorageClass::kWorkgroup);
@@ -68,43 +72,58 @@
 
 TEST_F(VariableTest, IsValid) {
   type::I32 t;
-  Variable v{Source{}, "my_var", StorageClass::kNone, &t};
+  Variable v{Source{}, "my_var", StorageClass::kNone,          &t,
+             false,    nullptr,  ast::VariableDecorationList{}};
   EXPECT_TRUE(v.IsValid());
 }
 
 TEST_F(VariableTest, IsValid_WithConstructor) {
   type::I32 t;
-  Variable v{Source{}, "my_var", StorageClass::kNone, &t};
-  v.set_constructor(create<IdentifierExpression>("ident"));
+  Variable v{Source{},
+             "my_var",
+             StorageClass::kNone,
+             &t,
+             false,
+             create<IdentifierExpression>("ident"),
+             ast::VariableDecorationList{}};
   EXPECT_TRUE(v.IsValid());
 }
 
 TEST_F(VariableTest, IsValid_MissinName) {
   type::I32 t;
-  Variable v{Source{}, "", StorageClass::kNone, &t};
+  Variable v{Source{}, "",      StorageClass::kNone,          &t,
+             false,    nullptr, ast::VariableDecorationList{}};
   EXPECT_FALSE(v.IsValid());
 }
 
 TEST_F(VariableTest, IsValid_MissingType) {
-  Variable v{Source{}, "x", StorageClass::kNone, nullptr};
+  Variable v{Source{}, "x",     StorageClass::kNone,          nullptr,
+             false,    nullptr, ast::VariableDecorationList{}};
   EXPECT_FALSE(v.IsValid());
 }
 
 TEST_F(VariableTest, IsValid_MissingBoth) {
-  Variable v{Source{}, "", StorageClass::kNone, nullptr};
+  Variable v{Source{}, "",      StorageClass::kNone,          nullptr,
+             false,    nullptr, ast::VariableDecorationList{}};
   EXPECT_FALSE(v.IsValid());
 }
 
 TEST_F(VariableTest, IsValid_InvalidConstructor) {
   type::I32 t;
-  Variable v{Source{}, "my_var", StorageClass::kNone, &t};
-  v.set_constructor(create<IdentifierExpression>(""));
+  Variable v{Source{},
+             "my_var",
+             StorageClass::kNone,
+             &t,
+             false,
+             create<IdentifierExpression>(""),
+             ast::VariableDecorationList{}};
   EXPECT_FALSE(v.IsValid());
 }
 
 TEST_F(VariableTest, to_str) {
   type::F32 t;
-  Variable v{Source{}, "my_var", StorageClass::kFunction, &t};
+  Variable v{Source{}, "my_var", StorageClass::kFunction,      &t,
+             false,    nullptr,  ast::VariableDecorationList{}};
   std::ostringstream out;
   v.to_str(out, 2);
   EXPECT_EQ(out.str(), R"(  Variable{
@@ -115,6 +134,58 @@
 )");
 }
 
+TEST_F(VariableTest, WithDecorations) {
+  type::F32 t;
+  auto* var = create<Variable>(
+      Source{}, "my_var", StorageClass::kFunction, &t, false, nullptr,
+      VariableDecorationList{
+          create<LocationDecoration>(1, Source{}),
+          create<BuiltinDecoration>(Builtin::kPosition, Source{}),
+          create<ConstantIdDecoration>(1200, Source{}),
+      });
+
+  EXPECT_TRUE(var->HasLocationDecoration());
+  EXPECT_TRUE(var->HasBuiltinDecoration());
+  EXPECT_TRUE(var->HasConstantIdDecoration());
+}
+
+TEST_F(VariableTest, ConstantId) {
+  type::F32 t;
+  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t,
+                               false, nullptr,
+                               VariableDecorationList{
+                                   create<ConstantIdDecoration>(1200, Source{}),
+                               });
+
+  EXPECT_EQ(var->constant_id(), 1200u);
+}
+
+TEST_F(VariableTest, Decorated_to_str) {
+  type::F32 t;
+  auto* var = create<Variable>(Source{}, "my_var", StorageClass::kFunction, &t,
+                               false, create<IdentifierExpression>("expr"),
+                               VariableDecorationList{
+                                   create<BindingDecoration>(2, Source{}),
+                                   create<SetDecoration>(1, Source{}),
+                               });
+
+  std::ostringstream out;
+  var->to_str(out, 2);
+  EXPECT_EQ(out.str(), R"(  Variable{
+    Decorations{
+      BindingDecoration{2}
+      SetDecoration{1}
+    }
+    my_var
+    function
+    __f32
+    {
+      Identifier[not set]{expr}
+    }
+  }
+)");
+}
+
 }  // namespace
 }  // namespace ast
 }  // namespace tint
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 18b4aad..1bbbe8b 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -20,7 +20,6 @@
 
 #include "src/ast/bool_literal.h"
 #include "src/ast/constructor_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/function.h"
 #include "src/ast/null_literal.h"
@@ -39,6 +38,7 @@
 #include "src/ast/type/u32_type.h"
 #include "src/ast/type/vector_type.h"
 #include "src/ast/uint_literal.h"
+#include "src/ast/variable.h"
 
 namespace tint {
 namespace inspector {
@@ -91,12 +91,7 @@
 std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
   std::map<uint32_t, Scalar> result;
   for (auto* var : module_.global_variables()) {
-    auto* decorated = var->As<ast::DecoratedVariable>();
-    if (decorated == nullptr) {
-      continue;
-    }
-
-    if (!decorated->HasConstantIdDecoration()) {
+    if (!var->HasConstantIdDecoration()) {
       continue;
     }
 
@@ -104,7 +99,7 @@
     // WGSL, so the validator should catch it. Thus here the inspector just
     // assumes all definitians of the constant id are the same, so only needs
     // to find the first reference to constant id.
-    uint32_t constant_id = decorated->constant_id();
+    uint32_t constant_id = var->constant_id();
     if (result.find(constant_id) != result.end()) {
       continue;
     }
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index 9014d26..46ac6e4 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -22,7 +22,6 @@
 #include "src/ast/call_expression.h"
 #include "src/ast/call_statement.h"
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
@@ -56,6 +55,7 @@
 #include "src/ast/type/vector_type.h"
 #include "src/ast/type/void_type.h"
 #include "src/ast/uint_literal.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/ast/variable_decoration.h"
 #include "src/ast/workgroup_decoration.h"
@@ -114,10 +114,22 @@
     for (auto inout : inout_vars) {
       std::string in, out;
       std::tie(in, out) = inout;
-      auto* in_var = create<ast::Variable>(
-          Source{}, in, ast::StorageClass::kInput, u32_type());
-      auto* out_var = create<ast::Variable>(
-          Source{}, out, ast::StorageClass::kOutput, u32_type());
+      auto* in_var =
+          create<ast::Variable>(Source{},                   // source
+                                in,                         // name
+                                ast::StorageClass::kInput,  // storage_class
+                                u32_type(),                 // type
+                                false,                      // is_const
+                                nullptr,                    // constructor
+                                ast::VariableDecorationList{});  // decorations
+      auto* out_var =
+          create<ast::Variable>(Source{},                    // source
+                                out,                         // name
+                                ast::StorageClass::kOutput,  // storage_class
+                                u32_type(),                  // type
+                                false,                       // is_const
+                                nullptr,                     // constructor
+                                ast::VariableDecorationList{});  // decorations
       mod()->AddGlobalVariable(in_var);
       mod()->AddGlobalVariable(out_var);
     }
@@ -187,17 +199,23 @@
                      uint32_t id,
                      ast::type::Type* type,
                      T* val) {
-    auto* dvar = create<ast::DecoratedVariable>(
-        create<ast::Variable>(Source{}, name, ast::StorageClass::kNone, type));
-    dvar->set_is_const(true);
-    ast::VariableDecorationList decos;
-    decos.push_back(create<ast::ConstantIdDecoration>(id, Source{}));
-    dvar->set_decorations(decos);
+    ast::Expression* constructor = nullptr;
     if (val) {
-      dvar->set_constructor(
-          create<ast::ScalarConstructorExpression>(MakeLiteral(type, val)));
+      constructor =
+          create<ast::ScalarConstructorExpression>(MakeLiteral(type, val));
     }
-    mod()->AddGlobalVariable(dvar);
+    auto* var = create<ast::Variable>(
+        Source{},                  // source
+        name,                      // name
+        ast::StorageClass::kNone,  // storage_class
+        type,                      // type
+        true,                      // is_const
+        constructor,               // constructor
+        ast::VariableDecorationList{
+            // decorations
+            create<ast::ConstantIdDecoration>(id, Source{}),
+        });
+    mod()->AddGlobalVariable(var);
   }
 
   /// @param type AST type of the literal, must resolve to BoolLiteral
@@ -348,13 +366,18 @@
                   ast::StorageClass storage_class,
                   uint32_t set,
                   uint32_t binding) {
-    auto* var = create<ast::DecoratedVariable>(
-        create<ast::Variable>(Source{}, name, storage_class, type));
-    ast::VariableDecorationList decorations;
-
-    decorations.push_back(create<ast::BindingDecoration>(binding, Source{}));
-    decorations.push_back(create<ast::SetDecoration>(set, Source{}));
-    var->set_decorations(decorations);
+    auto* var = create<ast::Variable>(
+        Source{},       // source
+        name,           // name
+        storage_class,  // storage_class
+        type,           // type
+        false,          // is_const
+        nullptr,        // constructor
+        ast::VariableDecorationList{
+            // decorations
+            create<ast::BindingDecoration>(binding, Source{}),
+            create<ast::SetDecoration>(set, Source{}),
+        });
 
     mod()->AddGlobalVariable(var);
   }
@@ -399,9 +422,14 @@
       ast::type::Type* member_type;
       std::tie(member_idx, member_type) = member;
       std::string member_name = StructMemberName(member_idx, member_type);
-      body->append(create<ast::VariableDeclStatement>(
-          create<ast::Variable>(Source{}, "local" + member_name,
-                                ast::StorageClass::kNone, member_type)));
+      body->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
+          Source{},                          // source
+          "local" + member_name,             // name
+          ast::StorageClass::kNone,          // storage_class
+          member_type,                       // type
+          false,                             // is_const
+          nullptr,                           // constructor
+          ast::VariableDecorationList{})));  // decorations
     }
 
     for (auto member : members) {
@@ -496,7 +524,13 @@
 
   void AddGlobalVariable(const std::string& name, ast::type::Type* type) {
     mod()->AddGlobalVariable(create<ast::Variable>(
-        Source{}, name, ast::StorageClass::kUniformConstant, type));
+        Source{},                             // source
+        name,                                 // name
+        ast::StorageClass::kUniformConstant,  // storage_class
+        type,                                 // type
+        false,                                // is_const
+        nullptr,                              // constructor
+        ast::VariableDecorationList{}));      // decorations
   }
 
   /// Adds a depth texture variable to the module
@@ -504,7 +538,13 @@
   /// @param type the type to use
   void AddDepthTexture(const std::string& name, ast::type::Type* type) {
     mod()->AddGlobalVariable(create<ast::Variable>(
-        Source{}, name, ast::StorageClass::kUniformConstant, type));
+        Source{},                             // source
+        name,                                 // name
+        ast::StorageClass::kUniformConstant,  // storage_class
+        type,                                 // type
+        false,                                // is_const
+        nullptr,                              // constructor
+        ast::VariableDecorationList{}));      // decorations
   }
 
   /// Generates a function that references a specific sampler variable
@@ -526,9 +566,14 @@
 
     auto* body = create<ast::BlockStatement>();
 
-    auto* call_result = create<ast::Variable>(Source{}, "sampler_result",
-                                              ast::StorageClass::kFunction,
-                                              vec_type(base_type, 4));
+    auto* call_result =
+        create<ast::Variable>(Source{},                        // source
+                              "sampler_result",                // name
+                              ast::StorageClass::kFunction,    // storage_class
+                              vec_type(base_type, 4),          // type
+                              false,                           // is_const
+                              nullptr,                         // constructor
+                              ast::VariableDecorationList{});  // decorations
     body->append(create<ast::VariableDeclStatement>(call_result));
 
     ast::ExpressionList call_params;
@@ -567,9 +612,14 @@
 
     auto* body = create<ast::BlockStatement>();
 
-    auto* call_result = create<ast::Variable>(Source{}, "sampler_result",
-                                              ast::StorageClass::kFunction,
-                                              vec_type(base_type, 4));
+    auto* call_result =
+        create<ast::Variable>(Source{},                        // source
+                              "sampler_result",                // name
+                              ast::StorageClass::kFunction,    // storage_class
+                              vec_type(base_type, 4),          // type
+                              false,                           // is_const
+                              nullptr,                         // constructor
+                              ast::VariableDecorationList{});  // decorations
     body->append(create<ast::VariableDeclStatement>(call_result));
 
     ast::ExpressionList call_params;
@@ -610,8 +660,14 @@
 
     auto* body = create<ast::BlockStatement>();
 
-    auto* call_result = create<ast::Variable>(
-        Source{}, "sampler_result", ast::StorageClass::kFunction, base_type);
+    auto* call_result =
+        create<ast::Variable>(Source{},                        // source
+                              "sampler_result",                // name
+                              ast::StorageClass::kFunction,    // storage_class
+                              base_type,                       // type
+                              false,                           // is_const
+                              nullptr,                         // constructor
+                              ast::VariableDecorationList{});  // decorations
     body->append(create<ast::VariableDeclStatement>(call_result));
 
     ast::ExpressionList call_params;
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 50bb0ab..be68f8e 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -803,9 +803,9 @@
         auto* ast_type = parser_impl_.ConvertType(param->type_id());
         if (ast_type != nullptr) {
           auto* ast_param = parser_impl_.MakeVariable(
-              param->result_id(), ast::StorageClass::kNone, ast_type);
+              param->result_id(), ast::StorageClass::kNone, ast_type, true,
+              nullptr, ast::VariableDecorationList{});
           // Parameters are treated as const declarations.
-          ast_param->set_is_const(true);
           ast_params.emplace_back(ast_param);
           // The value is accessible by name.
           identifier_values_.insert(param->result_id());
@@ -1864,16 +1864,18 @@
     if (failed()) {
       return false;
     }
-    auto* var = parser_impl_.MakeVariable(
-        inst.result_id(), ast::StorageClass::kFunction, var_store_type);
+    ast::Expression* constructor = nullptr;
     if (inst.NumInOperands() > 1) {
       // SPIR-V initializers are always constants.
       // (OpenCL also allows the ID of an OpVariable, but we don't handle that
       // here.)
-      var->set_constructor(
+      constructor =
           parser_impl_.MakeConstantExpression(inst.GetSingleWordInOperand(1))
-              .expr);
+              .expr;
     }
+    auto* var = parser_impl_.MakeVariable(
+        inst.result_id(), ast::StorageClass::kFunction, var_store_type, false,
+        constructor, ast::VariableDecorationList{});
     auto* var_decl_stmt = create<ast::VariableDeclStatement>(var);
     AddStatementForInstruction(var_decl_stmt, inst);
     // Save this as an already-named value.
@@ -2141,10 +2143,14 @@
   const std::string guard_name = block_info.flow_guard_name;
   if (!guard_name.empty()) {
     // Declare the guard variable just before the "if", initialized to true.
-    auto* guard_var = create<ast::Variable>(Source{}, guard_name,
-                                            ast::StorageClass::kFunction,
-                                            parser_impl_.Bool());
-    guard_var->set_constructor(MakeTrue());
+    auto* guard_var =
+        create<ast::Variable>(Source{},                        // source
+                              guard_name,                      // name
+                              ast::StorageClass::kFunction,    // storage_class
+                              parser_impl_.Bool(),             // type
+                              false,                           // is_const
+                              MakeTrue(),                      // constructor
+                              ast::VariableDecorationList{});  // decorations
     auto* guard_decl = create<ast::VariableDeclStatement>(guard_var);
     AddStatement(guard_decl);
   }
@@ -2674,8 +2680,9 @@
     assert(def_inst);
     auto* ast_type =
         RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
-    AddStatement(create<ast::VariableDeclStatement>(
-        parser_impl_.MakeVariable(id, ast::StorageClass::kFunction, ast_type)));
+    AddStatement(create<ast::VariableDeclStatement>(parser_impl_.MakeVariable(
+        id, ast::StorageClass::kFunction, ast_type, false, nullptr,
+        ast::VariableDecorationList{})));
     // Save this as an already-named value.
     identifier_values_.insert(id);
   }
@@ -2686,8 +2693,13 @@
     const auto phi_var_name = GetDefInfo(id)->phi_var;
     assert(!phi_var_name.empty());
     auto* var = create<ast::Variable>(
-        Source{}, phi_var_name, ast::StorageClass::kFunction,
-        parser_impl_.ConvertType(def_inst->type_id()));
+        Source{},                                       // source
+        phi_var_name,                                   // name
+        ast::StorageClass::kFunction,                   // storage_class
+        parser_impl_.ConvertType(def_inst->type_id()),  // type
+        false,                                          // is_const
+        nullptr,                                        // constructor
+        ast::VariableDecorationList{});                 // decorations
     AddStatement(create<ast::VariableDeclStatement>(var));
   }
 
@@ -2734,12 +2746,11 @@
     return false;
   }
   auto* ast_const = parser_impl_.MakeVariable(
-      inst.result_id(), ast::StorageClass::kNone, ast_expr.type);
+      inst.result_id(), ast::StorageClass::kNone, ast_expr.type, true,
+      ast_expr.expr, ast::VariableDecorationList{});
   if (!ast_const) {
     return false;
   }
-  ast_const->set_constructor(ast_expr.expr);
-  ast_const->set_is_const(true);
   AddStatementForInstruction(create<ast::VariableDeclStatement>(ast_const),
                              inst);
   // Save this as an already-named value.
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index 6c2bd66..a381b21 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -41,7 +41,6 @@
 #include "src/ast/builtin.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/set_decoration.h"
@@ -1064,8 +1063,6 @@
         break;
     }
     if (ast_type && ast_expr) {
-      auto* ast_var =
-          MakeVariable(inst.result_id(), ast::StorageClass::kNone, ast_type);
       ast::VariableDecorationList spec_id_decos;
       for (const auto& deco : GetDecorationsFor(inst.result_id())) {
         if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
@@ -1074,18 +1071,10 @@
           break;
         }
       }
-      if (spec_id_decos.empty()) {
-        // Register it as a named constant, without specialization id.
-        ast_var->set_is_const(true);
-        ast_var->set_constructor(ast_expr);
-        ast_module_.AddGlobalVariable(ast_var);
-      } else {
-        auto* ast_deco_var = create<ast::DecoratedVariable>(ast_var);
-        ast_deco_var->set_is_const(true);
-        ast_deco_var->set_constructor(ast_expr);
-        ast_deco_var->set_decorations(std::move(spec_id_decos));
-        ast_module_.AddGlobalVariable(ast_deco_var);
-      }
+      auto* ast_var =
+          MakeVariable(inst.result_id(), ast::StorageClass::kNone, ast_type,
+                       true, ast_expr, std::move(spec_id_decos));
+      ast_module_.AddGlobalVariable(ast_var);
       scalar_spec_constants_.insert(inst.result_id());
     }
   }
@@ -1190,15 +1179,17 @@
     auto* ast_store_type = ast_type->As<ast::type::Pointer>()->type();
     auto ast_storage_class =
         ast_type->As<ast::type::Pointer>()->storage_class();
-    auto* ast_var =
-        MakeVariable(var.result_id(), ast_storage_class, ast_store_type);
+    ast::Expression* ast_constructor = nullptr;
     if (var.NumInOperands() > 1) {
       // SPIR-V initializers are always constants.
       // (OpenCL also allows the ID of an OpVariable, but we don't handle that
       // here.)
-      ast_var->set_constructor(
-          MakeConstantExpression(var.GetSingleWordInOperand(1)).expr);
+      ast_constructor =
+          MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
     }
+    auto* ast_var =
+        MakeVariable(var.result_id(), ast_storage_class, ast_store_type, false,
+                     ast_constructor, ast::VariableDecorationList{});
     // TODO(dneto): initializers (a.k.a. constructor expression)
     ast_module_.AddGlobalVariable(ast_var);
   }
@@ -1208,23 +1199,26 @@
     // Make sure the variable has a name.
     namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id,
                                 "gl_Position");
-    auto* var = create<ast::DecoratedVariable>(MakeVariable(
+    auto* var = MakeVariable(
         builtin_position_.per_vertex_var_id,
         enum_converter_.ToStorageClass(builtin_position_.storage_class),
-        ConvertType(builtin_position_.member_type_id)));
-    ast::VariableDecorationList decos;
-    decos.push_back(
-        create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}));
-    var->set_decorations(std::move(decos));
+        ConvertType(builtin_position_.member_type_id), false, nullptr,
+        ast::VariableDecorationList{
+            create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}),
+        });
 
     ast_module_.AddGlobalVariable(var);
   }
   return success_;
 }
 
-ast::Variable* ParserImpl::MakeVariable(uint32_t id,
-                                        ast::StorageClass sc,
-                                        ast::type::Type* type) {
+ast::Variable* ParserImpl::MakeVariable(
+    uint32_t id,
+    ast::StorageClass sc,
+    ast::type::Type* type,
+    bool is_const,
+    ast::Expression* constructor,
+    ast::VariableDecorationList decorations) {
   if (type == nullptr) {
     Fail() << "internal error: can't make ast::Variable for null type";
     return nullptr;
@@ -1238,9 +1232,6 @@
     type = ast_module_.create<ast::type::AccessControl>(access, type);
   }
 
-  auto* ast_var = create<ast::Variable>(Source{}, namer_.Name(id), sc, type);
-
-  ast::VariableDecorationList ast_decorations;
   for (auto& deco : GetDecorationsFor(id)) {
     if (deco.empty()) {
       Fail() << "malformed decoration on ID " << id << ": it is empty";
@@ -1257,7 +1248,7 @@
       if (ast_builtin == ast::Builtin::kNone) {
         return nullptr;
       }
-      ast_decorations.emplace_back(
+      decorations.emplace_back(
           create<ast::BuiltinDecoration>(ast_builtin, Source{}));
     }
     if (deco[0] == SpvDecorationLocation) {
@@ -1266,7 +1257,7 @@
                << ": requires one literal operand";
         return nullptr;
       }
-      ast_decorations.emplace_back(
+      decorations.emplace_back(
           create<ast::LocationDecoration>(deco[1], Source{}));
     }
     if (deco[0] == SpvDecorationDescriptorSet) {
@@ -1275,8 +1266,7 @@
                << ": has no operand";
         return nullptr;
       }
-      ast_decorations.emplace_back(
-          create<ast::SetDecoration>(deco[1], Source{}));
+      decorations.emplace_back(create<ast::SetDecoration>(deco[1], Source{}));
     }
     if (deco[0] == SpvDecorationBinding) {
       if (deco.size() == 1) {
@@ -1284,16 +1274,18 @@
                << ": has no operand";
         return nullptr;
       }
-      ast_decorations.emplace_back(
+      decorations.emplace_back(
           create<ast::BindingDecoration>(deco[1], Source{}));
     }
   }
-  if (!ast_decorations.empty()) {
-    auto* decorated_var = create<ast::DecoratedVariable>(ast_var);
-    decorated_var->set_decorations(std::move(ast_decorations));
-    ast_var = std::move(decorated_var);
-  }
-  return ast_var;
+
+  return create<ast::Variable>(Source{},         // source
+                               namer_.Name(id),  // name
+                               sc,               // storage_class
+                               type,             // type
+                               is_const,         // is_const
+                               constructor,      // constructor
+                               decorations);     // decorations
 }
 
 TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
diff --git a/src/reader/spirv/parser_impl.h b/src/reader/spirv/parser_impl.h
index 2e9e9d7..4e2741d 100644
--- a/src/reader/spirv/parser_impl.h
+++ b/src/reader/spirv/parser_impl.h
@@ -291,10 +291,16 @@
   /// @param id the SPIR-V result ID
   /// @param sc the storage class, which cannot be ast::StorageClass::kNone
   /// @param type the type
+  /// @param is_const if true, the variable is const
+  /// @param constructor the variable constructor
+  /// @param decorations the variable decorations
   /// @returns a new Variable node, or null in the error case
   ast::Variable* MakeVariable(uint32_t id,
                               ast::StorageClass sc,
-                              ast::type::Type* type);
+                              ast::type::Type* type,
+                              bool is_const,
+                              ast::Expression* constructor,
+                              ast::VariableDecorationList decorations);
 
   /// Creates an AST expression node for a SPIR-V constant.
   /// @param id the SPIR-V ID of the constant
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index afe18d6..693d845 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -1141,7 +1141,7 @@
          %10 = OpVariable %ptr UniformConstant
 )",
                                                           R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1159,7 +1159,7 @@
          %10 = OpVariable %ptr_f_texture_1d UniformConstant
 )",
                                                           R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1175,7 +1175,7 @@
          %10 = OpVariable %ptr_f_storage_1d UniformConstant
 )",
                                                           R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1191,7 +1191,7 @@
          %10 = OpVariable %ptr_f_storage_1d UniformConstant
 )",
                                                           R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1343,7 +1343,7 @@
                         "%result = OpImageSampleImplicitLod "
                         "%v4float %sampled_image %coords12",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1352,7 +1352,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1376,7 +1376,7 @@
                         "%result = OpImageSampleImplicitLod "
                         "%v4float %sampled_image %coords123",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1385,7 +1385,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1420,7 +1420,7 @@
             "%result = OpImageSampleImplicitLod "
             "%v4float %sampled_image %coords12 ConstOffset %offsets2d",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1429,7 +1429,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1455,7 +1455,7 @@
             "%result = OpImageSampleImplicitLod "
             "%v4float %sampled_image %coords123 ConstOffset %offsets2d",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1464,7 +1464,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1499,7 +1499,7 @@
                         "%result = OpImageSampleImplicitLod "
                         "%v4float %sampled_image %coords12 Bias %float_7",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1508,7 +1508,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1533,7 +1533,7 @@
                         "%result = OpImageSampleImplicitLod "
                         "%v4float %sampled_image %coords123 Bias %float_7",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1542,7 +1542,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1580,7 +1580,7 @@
                         "%v4float %sampled_image %coords12 Bias|ConstOffset "
                         "%float_7 %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1589,7 +1589,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1615,7 +1615,7 @@
                         "%v4float %sampled_image %coords123 Bias|ConstOffset "
                         "%float_7 %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1624,7 +1624,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1672,7 +1672,7 @@
      %210 = OpImageSampleDrefImplicitLod %v4float %sampled_dref_image %coords12 %depth
 )",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1681,7 +1681,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1690,7 +1690,7 @@
     uniform_constant
     __depth_texture_2d
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{1}
@@ -1745,7 +1745,7 @@
                         "%result = OpImageSampleDrefImplicitLod "
                         "%v4float %sampled_image %coords12 %depth",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1754,7 +1754,7 @@
     uniform_constant
     __sampler_comparison
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1778,7 +1778,7 @@
                         "%result = OpImageSampleDrefImplicitLod "
                         "%v4float %sampled_image %coords123 %depth",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1787,7 +1787,7 @@
     uniform_constant
     __sampler_comparison
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1822,7 +1822,7 @@
             "%result = OpImageSampleDrefImplicitLod %v4float "
             "%sampled_image %coords12 %depth ConstOffset %offsets2d",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1831,7 +1831,7 @@
     uniform_constant
     __sampler_comparison
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1857,7 +1857,7 @@
             "%result = OpImageSampleDrefImplicitLod %v4float "
             "%sampled_image %coords123 %depth ConstOffset %offsets2d",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1866,7 +1866,7 @@
     uniform_constant
     __sampler_comparison
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1907,7 +1907,7 @@
                         "%result = OpImageSampleExplicitLod "
                         "%v4float %sampled_image %coords12 Lod %float_null",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1916,7 +1916,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1941,7 +1941,7 @@
                         "%result = OpImageSampleExplicitLod "
                         "%v4float %sampled_image %coords123 Lod %float_null",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1950,7 +1950,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -1988,7 +1988,7 @@
                         "%v4float %sampled_image %coords12 Lod|ConstOffset "
                         "%float_null %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -1997,7 +1997,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2024,7 +2024,7 @@
                         "%v4float %sampled_image %coords123 Lod|ConstOffset "
                         "%float_null %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2033,7 +2033,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2070,7 +2070,7 @@
             "%result = OpImageSampleExplicitLod "
             "%v4float %sampled_image %coords12 Grad %float_7 %float_null",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2079,7 +2079,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2106,7 +2106,7 @@
             "%result = OpImageSampleExplicitLod "
             "%v4float %sampled_image %coords123 Grad %float_7 %float_null",
             R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2115,7 +2115,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2154,7 +2154,7 @@
                         "%v4float %sampled_image %coords12 Grad|ConstOffset "
                         "%float_7 %float_null %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2163,7 +2163,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2192,7 +2192,7 @@
                         "%v4float %sampled_image %coords123 Grad|ConstOffset "
                         "%float_7 %float_null %offsets2d",
                         R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2201,7 +2201,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2248,7 +2248,7 @@
          "%result = OpImageSampleExplicitLod %v4float "
          "%sampled_image %vf12 Lod %f1",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2257,7 +2257,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2281,7 +2281,7 @@
          "%result = OpImageSampleExplicitLod %v4float "
          "%sampled_image %vf12 Lod %f1",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -2290,7 +2290,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2387,7 +2387,7 @@
         // OpImageWrite with no extra params
         {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2408,7 +2408,7 @@
         {"%float 2D 0 0 0 2 Rgba32f",
          "OpImageWrite %im %vu12 %vf1234 ConstOffset %offsets2d",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2437,7 +2437,7 @@
         // Source 1 component, dest 1 component
         {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %f1",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2457,7 +2457,7 @@
         // Source 2 component, dest 1 component
         {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2480,7 +2480,7 @@
         // Source 3 component, dest 1 component
         {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf123",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2503,7 +2503,7 @@
         // Source 4 component, dest 1 component
         {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2526,7 +2526,7 @@
         // Source 2 component, dest 2 component
         {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2546,7 +2546,7 @@
         // Source 3 component, dest 2 component
         {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf123",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2569,7 +2569,7 @@
         // Source 4 component, dest 2 component
         {"%float 2D 0 0 0 2 Rg32f", "OpImageWrite %im %vu12 %vf1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2593,7 +2593,7 @@
         // Source 4 component, dest 4 component
         {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vu12 %vf1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2759,7 +2759,7 @@
         // Sampled type is unsigned int, texel is unsigned int
         {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vu1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2779,7 +2779,7 @@
         // Sampled type is unsigned int, texel is signed int
         {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vu12 %vi1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2801,7 +2801,7 @@
         // Sampled type is signed int, texel is unsigned int
         {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vu1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2823,7 +2823,7 @@
         // Sampled type is signed int, texel is signed int
         {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vu12 %vi1234",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2847,7 +2847,7 @@
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
         // OpImageRead with no extra params
         {"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2875,7 +2875,7 @@
         // OpImageRead with ConstOffset
         {"%float 2D 0 0 0 2 Rgba32f",
          "%99 = OpImageRead %v4float %im %vu12 ConstOffset %offsets2d",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2908,7 +2908,7 @@
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
         // OpImageFetch with no extra params
         {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2936,7 +2936,7 @@
         // OpImageFetch with ConstOffset
         {"%float 2D 0 0 0 1 Unknown",
          "%99 = OpImageFetch %v4float %im %vu12 ConstOffset %offsets2d",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -2983,7 +2983,7 @@
 
         // OpImageFetch requires no conversion, float -> v4float
         {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3010,7 +3010,7 @@
     })"},
         // OpImageFetch requires no conversion, uint -> v4uint
         {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3037,7 +3037,7 @@
     })"},
         // OpImageFetch requires conversion, uint -> v4int
         {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3066,7 +3066,7 @@
     })"},
         // OpImageFetch requires no conversion, int -> v4int
         {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3093,7 +3093,7 @@
     })"},
         // OpImageFetch requires conversion, int -> v4uint
         {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3127,7 +3127,7 @@
 
         // OpImageRead requires no conversion, float -> v4float
         {"%float 2D 0 0 0 1 Rgba32f", "%99 = OpImageRead %v4float %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3154,7 +3154,7 @@
     })"},
         // OpImageRead requires no conversion, uint -> v4uint
         {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4uint %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3181,7 +3181,7 @@
     })"},
         // OpImageRead requires conversion, uint -> v4int
         {"%uint 2D 0 0 0 1 Rgba32ui", "%99 = OpImageRead %v4int %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3210,7 +3210,7 @@
     })"},
         // OpImageRead requires no conversion, int -> v4int
         {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4int %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3237,7 +3237,7 @@
     })"},
         // OpImageRead requires conversion, int -> v4uint
         {"%int 2D 0 0 0 1 Rgba32i", "%99 = OpImageRead %v4uint %im %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3273,7 +3273,7 @@
         {"%float 2D 0 0 0 1 Unknown",
          "%99 = OpImageSampleImplicitLod %v4float %sampled_image %vu12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -3282,7 +3282,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3312,7 +3312,7 @@
         {"%uint 2D 0 0 0 1 Unknown",
          "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -3321,7 +3321,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3351,7 +3351,7 @@
         {"%uint 2D 0 0 0 1 Unknown",
          "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -3360,7 +3360,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3392,7 +3392,7 @@
         {"%int 2D 0 0 0 1 Unknown",
          "%99 = OpImageSampleImplicitLod %v4int %sampled_image %vu12",
          R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{0}
       BindingDecoration{0}
@@ -3401,7 +3401,7 @@
     uniform_constant
     __sampler_sampler
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
@@ -3430,7 +3430,7 @@
         // OpImageSampleImplicitLod requires conversion, int -> v4uint
         {"%int 2D 0 0 0 1 Unknown",
          "%99 = OpImageSampleImplicitLod %v4uint %sampled_image %vu12",
-         R"(DecoratedVariable{
+         R"(Variable{
     Decorations{
       SetDecoration{2}
       BindingDecoration{1}
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index b80dc15..be335f1 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -199,7 +199,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -249,7 +249,7 @@
   EXPECT_EQ(position_info.per_vertex_var_id, 1u);
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{position}
     }
@@ -1146,7 +1146,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       LocationDecoration{3}
     }
@@ -1198,7 +1198,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       SetDecoration{3}
     }
@@ -1252,7 +1252,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{3}
     }
@@ -1501,7 +1501,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariableConst{
+  VariableConst{
     Decorations{
       ConstantIdDecoration{12}
     }
@@ -1526,7 +1526,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariableConst{
+  VariableConst{
     Decorations{
       ConstantIdDecoration{12}
     }
@@ -1551,7 +1551,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariableConst{
+  VariableConst{
     Decorations{
       ConstantIdDecoration{12}
     }
@@ -1576,7 +1576,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariableConst{
+  VariableConst{
     Decorations{
       ConstantIdDecoration{12}
     }
@@ -1601,7 +1601,7 @@
   EXPECT_TRUE(p->error().empty());
   const auto module_str = p->module().to_str();
   EXPECT_THAT(module_str, HasSubstr(R"(
-  DecoratedVariableConst{
+  VariableConst{
     Decorations{
       ConstantIdDecoration{12}
     }
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 8a3b076..67a4651 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -28,7 +28,6 @@
 #include "src/ast/call_expression.h"
 #include "src/ast/case_statement.h"
 #include "src/ast/continue_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/fallthrough_statement.h"
@@ -67,6 +66,7 @@
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/ast/workgroup_decoration.h"
 #include "src/reader/wgsl/lexer.h"
@@ -419,25 +419,25 @@
   if (!decl.matched)
     return Failure::kNoMatch;
 
-  auto* var = decl.value;
-
   auto var_decos = cast_decorations<ast::VariableDecoration>(decos);
   if (var_decos.errored)
     return Failure::kErrored;
 
-  if (var_decos.value.size() > 0) {
-    auto* dv = create<ast::DecoratedVariable>(var);
-    dv->set_decorations(var_decos.value);
-    var = dv;
-  }
-
+  ast::Expression* constructor = nullptr;
   if (match(Token::Type::kEqual)) {
     auto expr = expect_const_expr();
     if (expr.errored)
       return Failure::kErrored;
-    var->set_constructor(expr.value);
+    constructor = expr.value;
   }
-  return var;
+
+  return create<ast::Variable>(decl->source,                 // source
+                               decl->name,                   // name
+                               decl->storage_class,          // storage_class
+                               decl->type,                   // type
+                               false,                        // is_const
+                               constructor,                  // constructor
+                               std::move(var_decos.value));  // decorations
 }
 
 // global_constant_decl
@@ -452,10 +452,6 @@
   if (decl.errored)
     return Failure::kErrored;
 
-  auto* var = create<ast::Variable>(decl->source, decl->name,
-                                    ast::StorageClass::kNone, decl->type);
-  var->set_is_const(true);
-
   if (!expect(use, Token::Type::kEqual))
     return Failure::kErrored;
 
@@ -463,14 +459,18 @@
   if (init.errored)
     return Failure::kErrored;
 
-  var->set_constructor(init.value);
-
-  return var;
+  return create<ast::Variable>(decl->source,                    // source
+                               decl->name,                      // name
+                               ast::StorageClass::kNone,        // storage_class
+                               decl->type,                      // type
+                               true,                            // is_const
+                               init.value,                      // constructor
+                               ast::VariableDecorationList{});  // decorations
 }
 
 // variable_decl
 //   : VAR variable_storage_decoration? variable_ident_decl
-Maybe<ast::Variable*> ParserImpl::variable_decl() {
+Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl() {
   if (!match(Token::Type::kVar))
     return Failure::kNoMatch;
 
@@ -482,9 +482,9 @@
   if (decl.errored)
     return Failure::kErrored;
 
-  return create<ast::Variable>(decl->source, decl->name,
-                               sc.matched ? sc.value : ast::StorageClass::kNone,
-                               decl->type);
+  return VarDeclInfo{decl->source, decl->name,
+                     sc.matched ? sc.value : ast::StorageClass::kNone,
+                     decl->type};
 }
 
 // texture_sampler_types
@@ -1349,13 +1349,18 @@
 
   ast::VariableList ret;
   for (;;) {
-    auto* var = create<ast::Variable>(decl->source, decl->name,
-                                      ast::StorageClass::kNone, decl->type);
+    auto* var =
+        create<ast::Variable>(decl->source,                    // source
+                              decl->name,                      // name
+                              ast::StorageClass::kNone,        // storage_class
+                              decl->type,                      // type
+                              true,                            // is_const
+                              nullptr,                         // constructor
+                              ast::VariableDecorationList{});  // decorations
     // Formal parameters are treated like a const declaration where the
     // initializer value is provided by the call's argument.  The key point is
     // that it's not updatable after intially set.  This is unlike C or GLSL
     // which treat formal parameters like local variables that can be updated.
-    var->set_is_const(true);
     ret.push_back(var);
 
     if (!match(Token::Type::kComma))
@@ -1610,31 +1615,45 @@
     if (!constructor.matched)
       return add_error(peek(), "missing constructor for const declaration");
 
-    auto* var = create<ast::Variable>(decl->source, decl->name,
-                                      ast::StorageClass::kNone, decl->type);
-    var->set_is_const(true);
-    var->set_constructor(constructor.value);
+    auto* var =
+        create<ast::Variable>(decl->source,                    // source
+                              decl->name,                      // name
+                              ast::StorageClass::kNone,        // storage_class
+                              decl->type,                      // type
+                              true,                            // is_const
+                              constructor.value,               // constructor
+                              ast::VariableDecorationList{});  // decorations
 
     return create<ast::VariableDeclStatement>(decl->source, var);
   }
 
-  auto var = variable_decl();
-  if (var.errored)
+  auto decl = variable_decl();
+  if (decl.errored)
     return Failure::kErrored;
-  if (!var.matched)
+  if (!decl.matched)
     return Failure::kNoMatch;
 
+  ast::Expression* constructor = nullptr;
   if (match(Token::Type::kEqual)) {
-    auto constructor = logical_or_expression();
-    if (constructor.errored)
+    auto constructor_expr = logical_or_expression();
+    if (constructor_expr.errored)
       return Failure::kErrored;
-    if (!constructor.matched)
+    if (!constructor_expr.matched)
       return add_error(peek(), "missing constructor for variable declaration");
 
-    var->set_constructor(constructor.value);
+    constructor = constructor_expr.value;
   }
 
-  return create<ast::VariableDeclStatement>(var->source(), var.value);
+  auto* var =
+      create<ast::Variable>(decl->source,                    // source
+                            decl->name,                      // name
+                            decl->storage_class,             // storage_class
+                            decl->type,                      // type
+                            false,                           // is_const
+                            constructor,                     // constructor
+                            ast::VariableDecorationList{});  // decorations
+
+  return create<ast::VariableDeclStatement>(var->source(), var);
 }
 
 // if_stmt
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 3feea22..1bdd73b 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -262,6 +262,18 @@
     ast::type::Type* return_type;
   };
 
+  /// VarDeclInfo contains the parsed information for variable declaration.
+  struct VarDeclInfo {
+    /// Variable declaration source
+    Source source;
+    /// Variable name
+    std::string name;
+    /// Variable storage class
+    ast::StorageClass storage_class;
+    /// Variable type
+    ast::type::Type* type;
+  };
+
   /// Creates a new parser using the given file
   /// @param file the input source file to parse
   explicit ParserImpl(Source::File const* file);
@@ -356,8 +368,8 @@
   /// @returns the const object or nullptr
   Maybe<ast::Variable*> global_constant_decl();
   /// Parses a `variable_decl` grammar element
-  /// @returns the parsed variable or nullptr otherwise
-  Maybe<ast::Variable*> variable_decl();
+  /// @returns the parsed variable declaration info
+  Maybe<VarDeclInfo> variable_decl();
   /// Parses a `variable_ident_decl` grammar element, erroring on parse
   /// failure.
   /// @param use a description of what was being parsed if an error was raised.
diff --git a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
index 564b138..5e2804b 100644
--- a/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -13,8 +13,8 @@
 // limitations under the License.
 
 #include "gtest/gtest.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/type/f32_type.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decoration.h"
 #include "src/reader/wgsl/parser_impl.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
diff --git a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
index f095270..a42c8d3 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -13,9 +13,9 @@
 // limitations under the License.
 
 #include "gtest/gtest.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type/f32_type.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decoration.h"
 #include "src/reader/wgsl/parser_impl.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
@@ -46,7 +46,6 @@
   EXPECT_EQ(e->source().range.end.column, 11u);
 
   ASSERT_EQ(e->constructor(), nullptr);
-  ASSERT_FALSE(e->Is<ast::DecoratedVariable>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
@@ -72,8 +71,6 @@
   ASSERT_NE(e->constructor(), nullptr);
   ASSERT_TRUE(e->constructor()->Is<ast::ConstructorExpression>());
   ASSERT_TRUE(e->constructor()->Is<ast::ScalarConstructorExpression>());
-
-  ASSERT_FALSE(e->Is<ast::DecoratedVariable>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithDecoration) {
@@ -86,7 +83,6 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
 
   EXPECT_EQ(e->name(), "a");
   ASSERT_NE(e->type(), nullptr);
@@ -100,10 +96,7 @@
 
   ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
-  auto* v = e->As<ast::DecoratedVariable>();
-
-  auto& decorations = v->decorations();
+  auto& decorations = e->decorations();
   ASSERT_EQ(decorations.size(), 2u);
   ASSERT_TRUE(decorations[0]->Is<ast::BindingDecoration>());
   ASSERT_TRUE(decorations[1]->Is<ast::SetDecoration>());
@@ -120,7 +113,6 @@
   EXPECT_TRUE(e.matched);
   EXPECT_FALSE(e.errored);
   ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
 
   EXPECT_EQ(e->name(), "a");
   ASSERT_NE(e->type(), nullptr);
@@ -134,10 +126,7 @@
 
   ASSERT_EQ(e->constructor(), nullptr);
 
-  ASSERT_TRUE(e->Is<ast::DecoratedVariable>());
-  auto* v = e->As<ast::DecoratedVariable>();
-
-  auto& decorations = v->decorations();
+  auto& decorations = e->decorations();
   ASSERT_EQ(decorations.size(), 2u);
   ASSERT_TRUE(decorations[0]->Is<ast::BindingDecoration>());
   ASSERT_TRUE(decorations[1]->Is<ast::SetDecoration>());
diff --git a/src/reader/wgsl/parser_impl_variable_decl_test.cc b/src/reader/wgsl/parser_impl_variable_decl_test.cc
index f1a9ea6..3e30af0 100644
--- a/src/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -25,25 +25,23 @@
 
 TEST_F(ParserImplTest, VariableDecl_Parses) {
   auto p = parser("var my_var : f32");
-  auto var = p->variable_decl();
+  auto v = p->variable_decl();
   EXPECT_FALSE(p->has_error());
-  EXPECT_TRUE(var.matched);
-  EXPECT_FALSE(var.errored);
-  ASSERT_NE(var.value, nullptr);
-  EXPECT_EQ(var->name(), "my_var");
-  EXPECT_NE(var->type(), nullptr);
-  EXPECT_TRUE(var->type()->Is<ast::type::F32>());
+  EXPECT_TRUE(v.matched);
+  EXPECT_FALSE(v.errored);
+  EXPECT_EQ(v->name, "my_var");
+  EXPECT_NE(v->type, nullptr);
+  EXPECT_TRUE(v->type->Is<ast::type::F32>());
 
-  EXPECT_EQ(var->source().range.begin.line, 1u);
-  EXPECT_EQ(var->source().range.begin.column, 5u);
-  EXPECT_EQ(var->source().range.end.line, 1u);
-  EXPECT_EQ(var->source().range.end.column, 11u);
+  EXPECT_EQ(v->source.range.begin.line, 1u);
+  EXPECT_EQ(v->source.range.begin.column, 5u);
+  EXPECT_EQ(v->source.range.end.line, 1u);
+  EXPECT_EQ(v->source.range.end.column, 11u);
 }
 
 TEST_F(ParserImplTest, VariableDecl_MissingVar) {
   auto p = parser("my_var : f32");
   auto v = p->variable_decl();
-  EXPECT_EQ(v.value, nullptr);
   EXPECT_FALSE(v.matched);
   EXPECT_FALSE(v.errored);
   EXPECT_FALSE(p->has_error());
@@ -58,7 +56,6 @@
   EXPECT_FALSE(v.matched);
   EXPECT_TRUE(v.errored);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(v.value, nullptr);
   EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration");
 }
 
@@ -68,15 +65,14 @@
   EXPECT_TRUE(v.matched);
   EXPECT_FALSE(v.errored);
   EXPECT_FALSE(p->has_error());
-  ASSERT_NE(v.value, nullptr);
-  EXPECT_EQ(v->name(), "my_var");
-  EXPECT_TRUE(v->type()->Is<ast::type::F32>());
-  EXPECT_EQ(v->storage_class(), ast::StorageClass::kPrivate);
+  EXPECT_EQ(v->name, "my_var");
+  EXPECT_TRUE(v->type->Is<ast::type::F32>());
+  EXPECT_EQ(v->storage_class, ast::StorageClass::kPrivate);
 
-  EXPECT_EQ(v->source().range.begin.line, 1u);
-  EXPECT_EQ(v->source().range.begin.column, 14u);
-  EXPECT_EQ(v->source().range.end.line, 1u);
-  EXPECT_EQ(v->source().range.end.column, 20u);
+  EXPECT_EQ(v->source.range.begin.line, 1u);
+  EXPECT_EQ(v->source.range.begin.column, 14u);
+  EXPECT_EQ(v->source.range.end.line, 1u);
+  EXPECT_EQ(v->source.range.end.column, 20u);
 }
 
 TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
@@ -85,7 +81,6 @@
   EXPECT_FALSE(v.matched);
   EXPECT_TRUE(v.errored);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(v.value, nullptr);
   EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
 }
 
diff --git a/src/scope_stack_test.cc b/src/scope_stack_test.cc
index 55ecb5d..5f02f40 100644
--- a/src/scope_stack_test.cc
+++ b/src/scope_stack_test.cc
@@ -33,8 +33,8 @@
 
 TEST_F(ScopeStackTest, Global_SetWithPointer) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "test", ast::StorageClass::kNone, &f32);
-  v.set_name("my_var");
+  ast::Variable v(Source{}, "my_var", ast::StorageClass::kNone, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   ScopeStack<ast::Variable*> s;
   s.set_global("var", &v);
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index 2bb7f5b..6e1f171 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -122,8 +122,7 @@
       Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
       Const("c", ast::StorageClass::kFunction, ty.u32);
       Const("b", ast::StorageClass::kFunction,
-            ty.pointer<f32>(ast::StorageClass::kFunction))
-          ->set_constructor(Index("a", "c"));
+            ty.pointer<f32>(ast::StorageClass::kFunction), Index("a", "c"), {});
     }
   };
 
@@ -171,8 +170,8 @@
       Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
       Var("b", ast::StorageClass::kFunction, ty.array<f32, 5>());
       Var("i", ast::StorageClass::kFunction, ty.u32);
-      Const("c", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", Index("b", "i")));
+      Const("c", ast::StorageClass::kFunction, ty.f32,
+            Index("a", Index("b", "i")), {});
     }
   };
 
@@ -241,8 +240,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.array(ty.f32, 3));
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", 1u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", 1u), {});
     }
   };
 
@@ -274,8 +272,8 @@
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
       Var("c", ast::StorageClass::kFunction, ty.u32);
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", Add("c", Sub(2u, 3u))));
+      Var("b", ast::StorageClass::kFunction, ty.f32,
+          Index("a", Add("c", Sub(2u, 3u))), {});
     }
   };
 
@@ -340,8 +338,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", -1));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", -1), {});
     }
   };
 
@@ -371,8 +368,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.array<f32, 3>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", 3u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", 3u), {});
     }
   };
 
@@ -402,8 +398,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", 1u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", 1u), {});
     }
   };
 
@@ -435,8 +430,8 @@
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
       Var("c", ast::StorageClass::kFunction, ty.u32);
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", Add("c", Sub(2u, 3u))));
+      Var("b", ast::StorageClass::kFunction, ty.f32,
+          Index("a", Add("c", Sub(2u, 3u))), {});
     }
   };
 
@@ -499,8 +494,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", -1));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", -1), {});
     }
   };
 
@@ -530,8 +524,7 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.vec3<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index("a", 3u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index("a", 3u), {});
     }
   };
 
@@ -561,8 +554,8 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", 2u), 1u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index(Index("a", 2u), 1u),
+          {});
     }
   };
 
@@ -607,8 +600,8 @@
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
       Var("c", ast::StorageClass::kFunction, ty.u32);
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", Add("c", Sub(2u, 3u))), 1u));
+      Var("b", ast::StorageClass::kFunction, ty.f32,
+          Index(Index("a", Add("c", Sub(2u, 3u))), 1u), {});
     }
   };
 
@@ -687,8 +680,8 @@
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
       Var("c", ast::StorageClass::kFunction, ty.u32);
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", 1u), Add("c", Sub(2u, 3u))));
+      Var("b", ast::StorageClass::kFunction, ty.f32,
+          Index(Index("a", 1u), Add("c", Sub(2u, 3u))), {});
     }
   };
 
@@ -765,8 +758,8 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", -1), 1));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index(Index("a", -1), 1),
+          {});
     }
   };
 
@@ -809,8 +802,8 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", 2), -1));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index(Index("a", 2), -1),
+          {});
     }
   };
 
@@ -853,8 +846,8 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", 5u), 1u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index(Index("a", 5u), 1u),
+          {});
     }
   };
 
@@ -897,8 +890,8 @@
   struct Builder : ModuleBuilder {
     void Build() override {
       Var("a", ast::StorageClass::kFunction, ty.mat3x2<f32>());
-      Var("b", ast::StorageClass::kFunction, ty.f32)
-          ->set_constructor(Index(Index("a", 2u), 5u));
+      Var("b", ast::StorageClass::kFunction, ty.f32, Index(Index("a", 2u), 5u),
+          {});
     }
   };
 
diff --git a/src/transform/emit_vertex_point_size.cc b/src/transform/emit_vertex_point_size.cc
index 7d69cb5..bc25ede 100644
--- a/src/transform/emit_vertex_point_size.cc
+++ b/src/transform/emit_vertex_point_size.cc
@@ -19,12 +19,12 @@
 
 #include "src/ast/assignment_statement.h"
 #include "src/ast/block_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type_manager.h"
+#include "src/ast/variable.h"
 
 namespace tint {
 namespace transform {
@@ -51,11 +51,17 @@
 
   // Declare the pointsize builtin output variable.
   auto* pointsize_var =
-      mod->create<ast::DecoratedVariable>(mod->create<ast::Variable>(
-          Source{}, kPointSizeVar, ast::StorageClass::kOutput, f32));
-  pointsize_var->set_decorations({
-      mod->create<ast::BuiltinDecoration>(ast::Builtin::kPointSize, Source{}),
-  });
+      mod->create<ast::Variable>(Source{},                    // source
+                                 kPointSizeVar,               // name
+                                 ast::StorageClass::kOutput,  // storage_class
+                                 f32,                         // type
+                                 false,                       // is_const
+                                 nullptr,                     // constructor
+                                 ast::VariableDecorationList{
+                                     // decorations
+                                     mod->create<ast::BuiltinDecoration>(
+                                         ast::Builtin::kPointSize, Source{}),
+                                 });
   mod->AddGlobalVariable(pointsize_var);
 
   // Build the AST expression & statement for assigning pointsize one.
diff --git a/src/transform/emit_vertex_point_size_test.cc b/src/transform/emit_vertex_point_size_test.cc
index 55eebf2..7a08e5f 100644
--- a/src/transform/emit_vertex_point_size_test.cc
+++ b/src/transform/emit_vertex_point_size_test.cc
@@ -83,7 +83,7 @@
       << diag::Formatter().format(result.diagnostics);
 
   auto* expected = R"(Module{
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{pointsize}
     }
@@ -148,7 +148,7 @@
       << diag::Formatter().format(result.diagnostics);
 
   auto* expected = R"(Module{
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{pointsize}
     }
diff --git a/src/transform/first_index_offset.cc b/src/transform/first_index_offset.cc
index 37014d0..8738b7e 100644
--- a/src/transform/first_index_offset.cc
+++ b/src/transform/first_index_offset.cc
@@ -27,7 +27,6 @@
 #include "src/ast/case_statement.h"
 #include "src/ast/clone_context.h"
 #include "src/ast/constructor_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/expression.h"
 #include "src/ast/fallthrough_statement.h"
@@ -62,18 +61,17 @@
 constexpr char kFirstInstanceName[] = "tint_first_instance_index";
 constexpr char kIndexOffsetPrefix[] = "tint_first_index_offset_";
 
-ast::DecoratedVariable* clone_variable_with_new_name(ast::CloneContext* ctx,
-                                                     ast::DecoratedVariable* in,
-                                                     std::string new_name) {
-  auto* var = ctx->mod->create<ast::Variable>(ctx->Clone(in->source()),
-                                              new_name, in->storage_class(),
-                                              ctx->Clone(in->type()));
-  var->set_is_const(in->is_const());
-  var->set_constructor(ctx->Clone(in->constructor()));
-
-  auto* out = ctx->mod->create<ast::DecoratedVariable>(var);
-  out->set_decorations(ctx->Clone(in->decorations()));
-  return out;
+ast::Variable* clone_variable_with_new_name(ast::CloneContext* ctx,
+                                            ast::Variable* in,
+                                            std::string new_name) {
+  return ctx->mod->create<ast::Variable>(
+      ctx->Clone(in->source()),        // source
+      new_name,                        // name
+      in->storage_class(),             // storage_class
+      ctx->Clone(in->type()),          // type
+      in->is_const(),                  // is_const
+      ctx->Clone(in->constructor()),   // constructor
+      ctx->Clone(in->decorations()));  // decorations
 }
 
 }  // namespace
@@ -86,7 +84,7 @@
 Transform::Output FirstIndexOffset::Run(ast::Module* in) {
   // First do a quick check to see if the transform has already been applied.
   for (ast::Variable* var : in->global_variables()) {
-    if (auto* dec_var = var->As<ast::DecoratedVariable>()) {
+    if (auto* dec_var = var->As<ast::Variable>()) {
       if (dec_var->name() == kBufferName) {
         diag::Diagnostic err;
         err.message = "First index offset transform has already been applied.";
@@ -129,7 +127,7 @@
   // a CreateFirstIndexOffset() statement to each function that uses one of
   // these builtins.
   ast::CloneContext ctx(&out.module);
-  ctx.ReplaceAll([&](ast::DecoratedVariable* var) -> ast::DecoratedVariable* {
+  ctx.ReplaceAll([&](ast::Variable* var) -> ast::Variable* {
     for (ast::VariableDecoration* dec : var->decorations()) {
       if (auto* blt_dec = dec->As<ast::BuiltinDecoration>()) {
         ast::Builtin blt_type = blt_dec->value();
@@ -229,13 +227,17 @@
       kStructName,
       mod->create<ast::Struct>(std::move(decos), std::move(members)));
 
-  auto* idx_var =
-      mod->create<ast::DecoratedVariable>(mod->create<ast::Variable>(
-          Source{}, kBufferName, ast::StorageClass::kUniform, struct_type));
-  idx_var->set_decorations({
-      mod->create<ast::BindingDecoration>(binding_, Source{}),
-      mod->create<ast::SetDecoration>(set_, Source{}),
-  });
+  auto* idx_var = mod->create<ast::Variable>(
+      Source{},                     // source
+      kBufferName,                  // name
+      ast::StorageClass::kUniform,  // storage_class
+      struct_type,                  // type
+      false,                        // is_const
+      nullptr,                      // constructor
+      ast::VariableDecorationList{
+          mod->create<ast::BindingDecoration>(binding_, Source{}),
+          mod->create<ast::SetDecoration>(set_, Source{}),
+      });  // decorations
 
   mod->AddGlobalVariable(idx_var);
 
@@ -250,16 +252,20 @@
     ast::Variable* buffer_var,
     ast::Module* mod) {
   auto* buffer = mod->create<ast::IdentifierExpression>(buffer_var->name());
-  auto* var = mod->create<ast::Variable>(Source{}, original_name,
-                                         ast::StorageClass::kNone,
-                                         mod->create<ast::type::U32>());
-
-  var->set_is_const(true);
-  var->set_constructor(mod->create<ast::BinaryExpression>(
+  auto* constructor = mod->create<ast::BinaryExpression>(
       ast::BinaryOp::kAdd,
-      mod->create<ast::IdentifierExpression>(kIndexOffsetPrefix + var->name()),
+      mod->create<ast::IdentifierExpression>(kIndexOffsetPrefix +
+                                             original_name),
       mod->create<ast::MemberAccessorExpression>(
-          buffer, mod->create<ast::IdentifierExpression>(field_name))));
+          buffer, mod->create<ast::IdentifierExpression>(field_name)));
+  auto* var =
+      mod->create<ast::Variable>(Source{},                  // source
+                                 original_name,             // name
+                                 ast::StorageClass::kNone,  // storage_class
+                                 mod->create<ast::type::U32>(),   // type
+                                 true,                            // is_const
+                                 constructor,                     // constructor
+                                 ast::VariableDecorationList{});  // decorations
   return mod->create<ast::VariableDeclStatement>(var);
 }
 
diff --git a/src/transform/first_index_offset_test.cc b/src/transform/first_index_offset_test.cc
index b1dbdd0..c3b857c 100644
--- a/src/transform/first_index_offset_test.cc
+++ b/src/transform/first_index_offset_test.cc
@@ -25,7 +25,6 @@
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/call_expression.h"
 #include "src/ast/call_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/module.h"
@@ -52,12 +51,9 @@
 
  protected:
   void AddBuiltinInput(const std::string& name, ast::Builtin builtin) {
-    auto* var = Var(name, ast::StorageClass::kInput, ty.u32);
-    auto* dec_var = create<ast::DecoratedVariable>(var);
-    ast::VariableDecorationList decs;
-    decs.push_back(create<ast::BuiltinDecoration>(builtin, Source{}));
-    dec_var->set_decorations(std::move(decs));
-    mod->AddGlobalVariable(dec_var);
+    mod->AddGlobalVariable(
+        Var(name, ast::StorageClass::kInput, ty.u32, nullptr,
+            {create<ast::BuiltinDecoration>(builtin, Source{})}));
   }
 
   ast::Function* AddFunction(const std::string& name,
@@ -141,7 +137,7 @@
     [[block]]
     StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32}
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -149,7 +145,7 @@
     in
     __u32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{1}
       SetDecoration{2}
@@ -216,7 +212,7 @@
     [[block]]
     StructMember{[[ offset 0 ]] tint_first_instance_index: __u32}
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{instance_idx}
     }
@@ -224,7 +220,7 @@
     in
     __u32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{1}
       SetDecoration{7}
@@ -296,7 +292,7 @@
     StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32}
     StructMember{[[ offset 4 ]] tint_first_instance_index: __u32}
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{instance_idx}
     }
@@ -304,7 +300,7 @@
     in
     __u32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -312,7 +308,7 @@
     in
     __u32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{1}
       SetDecoration{7}
@@ -376,7 +372,7 @@
     [[block]]
     StructMember{[[ offset 0 ]] tint_first_vertex_index: __u32}
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -384,7 +380,7 @@
     in
     __u32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{2}
       SetDecoration{2}
diff --git a/src/transform/vertex_pulling.cc b/src/transform/vertex_pulling.cc
index 8be6582..d35f3d8 100644
--- a/src/transform/vertex_pulling.cc
+++ b/src/transform/vertex_pulling.cc
@@ -20,7 +20,6 @@
 #include "src/ast/assignment_statement.h"
 #include "src/ast/binary_expression.h"
 #include "src/ast/bitcast_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/member_accessor_expression.h"
 #include "src/ast/scalar_constructor_expression.h"
 #include "src/ast/stride_decoration.h"
@@ -37,6 +36,7 @@
 #include "src/ast/type/vector_type.h"
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/uint_literal.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 
 namespace tint {
@@ -143,13 +143,11 @@
       continue;
     }
 
-    if (auto* decorated = v->As<ast::DecoratedVariable>()) {
-      for (auto* d : decorated->decorations()) {
-        if (auto* builtin = d->As<ast::BuiltinDecoration>()) {
-          if (builtin->value() == ast::Builtin::kVertexIdx) {
-            vertex_index_name = v->name();
-            return;
-          }
+    for (auto* d : v->decorations()) {
+      if (auto* builtin = d->As<ast::BuiltinDecoration>()) {
+        if (builtin->value() == ast::Builtin::kVertexIdx) {
+          vertex_index_name = v->name();
+          return;
         }
       }
     }
@@ -158,14 +156,19 @@
   // We didn't find a vertex index builtin, so create one
   vertex_index_name = kDefaultVertexIndexName;
 
-  auto* var = mod->create<ast::DecoratedVariable>(mod->create<ast::Variable>(
-      Source{}, vertex_index_name, ast::StorageClass::kInput, GetI32Type()));
+  auto* var =
+      mod->create<ast::Variable>(Source{},                   // source
+                                 vertex_index_name,          // name
+                                 ast::StorageClass::kInput,  // storage_class
+                                 GetI32Type(),               // type
+                                 false,                      // is_const
+                                 nullptr,                    // constructor
+                                 ast::VariableDecorationList{
+                                     // decorations
+                                     mod->create<ast::BuiltinDecoration>(
+                                         ast::Builtin::kVertexIdx, Source{}),
+                                 });
 
-  ast::VariableDecorationList decorations;
-  decorations.push_back(
-      mod->create<ast::BuiltinDecoration>(ast::Builtin::kVertexIdx, Source{}));
-
-  var->set_decorations(std::move(decorations));
   mod->AddGlobalVariable(var);
 }
 
@@ -187,13 +190,11 @@
       continue;
     }
 
-    if (auto* decorated = v->As<ast::DecoratedVariable>()) {
-      for (auto* d : decorated->decorations()) {
-        if (auto* builtin = d->As<ast::BuiltinDecoration>()) {
-          if (builtin->value() == ast::Builtin::kInstanceIdx) {
-            instance_index_name = v->name();
-            return;
-          }
+    for (auto* d : v->decorations()) {
+      if (auto* builtin = d->As<ast::BuiltinDecoration>()) {
+        if (builtin->value() == ast::Builtin::kInstanceIdx) {
+          instance_index_name = v->name();
+          return;
         }
       }
     }
@@ -202,14 +203,18 @@
   // We didn't find an instance index builtin, so create one
   instance_index_name = kDefaultInstanceIndexName;
 
-  auto* var = mod->create<ast::DecoratedVariable>(mod->create<ast::Variable>(
-      Source{}, instance_index_name, ast::StorageClass::kInput, GetI32Type()));
-
-  ast::VariableDecorationList decorations;
-  decorations.push_back(mod->create<ast::BuiltinDecoration>(
-      ast::Builtin::kInstanceIdx, Source{}));
-
-  var->set_decorations(std::move(decorations));
+  auto* var =
+      mod->create<ast::Variable>(Source{},                   // source
+                                 instance_index_name,        // name
+                                 ast::StorageClass::kInput,  // storage_class
+                                 GetI32Type(),               // type
+                                 false,                      // is_const
+                                 nullptr,                    // constructor
+                                 ast::VariableDecorationList{
+                                     // decorations
+                                     mod->create<ast::BuiltinDecoration>(
+                                         ast::Builtin::kInstanceIdx, Source{}),
+                                 });
   mod->AddGlobalVariable(var);
 }
 
@@ -219,18 +224,22 @@
       continue;
     }
 
-    if (auto* decorated = v->As<ast::DecoratedVariable>()) {
-      for (auto* d : decorated->decorations()) {
-        if (auto* l = d->As<ast::LocationDecoration>()) {
-          uint32_t location = l->value();
-          // This is where the replacement happens. Expressions use identifier
-          // strings instead of pointers, so we don't need to update any other
-          // place in the AST.
-          v = mod->create<ast::Variable>(
-              Source{}, v->name(), ast::StorageClass::kPrivate, v->type());
-          location_to_var[location] = v;
-          break;
-        }
+    for (auto* d : v->decorations()) {
+      if (auto* l = d->As<ast::LocationDecoration>()) {
+        uint32_t location = l->value();
+        // This is where the replacement happens. Expressions use identifier
+        // strings instead of pointers, so we don't need to update any other
+        // place in the AST.
+        v = mod->create<ast::Variable>(
+            Source{},                        // source
+            v->name(),                       // name
+            ast::StorageClass::kPrivate,     // storage_class
+            v->type(),                       // type
+            false,                           // is_const
+            nullptr,                         // constructor
+            ast::VariableDecorationList{});  // decorations
+        location_to_var[location] = v;
+        break;
       }
     }
   }
@@ -263,17 +272,18 @@
 
   for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
     // The decorated variable with struct type
-    auto* var = mod->create<ast::DecoratedVariable>(mod->create<ast::Variable>(
-        Source{}, GetVertexBufferName(i), ast::StorageClass::kStorageBuffer,
-        struct_type));
-
-    // Add decorations
-    ast::VariableDecorationList decorations;
-    decorations.push_back(mod->create<ast::BindingDecoration>(i, Source{}));
-    decorations.push_back(
-        mod->create<ast::SetDecoration>(cfg.pulling_set, Source{}));
-    var->set_decorations(std::move(decorations));
-
+    auto* var = mod->create<ast::Variable>(
+        Source{},                           // source
+        GetVertexBufferName(i),             // name
+        ast::StorageClass::kStorageBuffer,  // storage_class
+        struct_type,                        // type
+        false,                              // is_const
+        nullptr,                            // constructor
+        ast::VariableDecorationList{
+            // decorations
+            mod->create<ast::BindingDecoration>(i, Source{}),
+            mod->create<ast::SetDecoration>(cfg.pulling_set, Source{}),
+        });
     mod->AddGlobalVariable(var);
   }
   mod->AddConstructedType(struct_type);
@@ -288,9 +298,15 @@
   auto* block = mod->create<ast::BlockStatement>();
 
   // Declare the |kPullingPosVarName| variable in the shader
-  auto* pos_declaration = mod->create<ast::VariableDeclStatement>(
-      mod->create<ast::Variable>(Source{}, kPullingPosVarName,
-                                 ast::StorageClass::kFunction, GetI32Type()));
+  auto* pos_declaration =
+      mod->create<ast::VariableDeclStatement>(mod->create<ast::Variable>(
+          Source{},                         // source
+          kPullingPosVarName,               // name
+          ast::StorageClass::kFunction,     // storage_class
+          GetI32Type(),                     // type
+          false,                            // is_const
+          nullptr,                          // constructor
+          ast::VariableDecorationList{}));  // decorations
 
   // |kPullingPosVarName| refers to the byte location of the current read. We
   // declare a variable in the shader to avoid having to reuse Expression
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index ab16882..8f2a177 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -17,7 +17,6 @@
 #include <utility>
 
 #include "gtest/gtest.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/function.h"
 #include "src/ast/pipeline_stage.h"
 #include "src/ast/stage_decoration.h"
@@ -25,6 +24,7 @@
 #include "src/ast/type/f32_type.h"
 #include "src/ast/type/i32_type.h"
 #include "src/ast/type/void_type.h"
+#include "src/ast/variable.h"
 #include "src/diagnostic/formatter.h"
 #include "src/transform/manager.h"
 #include "src/type_determiner.h"
@@ -69,13 +69,18 @@
   void AddVertexInputVariable(uint32_t location,
                               std::string name,
                               ast::type::Type* type) {
-    auto* var = create<ast::DecoratedVariable>(
-        create<ast::Variable>(Source{}, name, ast::StorageClass::kInput, type));
+    auto* var = create<ast::Variable>(
+        Source{},                   // source
+        name,                       // name
+        ast::StorageClass::kInput,  // storage_class
+        type,                       // type
+        false,                      // is_const
+        nullptr,                    // constructor
+        ast::VariableDecorationList{
+            // decorations
+            create<ast::LocationDecoration>(location, Source{}),
+        });
 
-    ast::VariableDecorationList decorations;
-    decorations.push_back(create<ast::LocationDecoration>(location, Source{}));
-
-    var->set_decorations(decorations);
     mod_->AddGlobalVariable(var);
   }
 
@@ -171,7 +176,7 @@
     private
     __f32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -179,7 +184,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{4}
@@ -257,7 +262,7 @@
     private
     __f32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{instance_idx}
     }
@@ -265,7 +270,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{4}
@@ -343,7 +348,7 @@
     private
     __f32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -351,7 +356,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{5}
@@ -416,31 +421,30 @@
   AddVertexInputVariable(1, "var_b", &f32);
 
   ast::type::I32 i32;
-  {
-    auto* vertex_index_var =
-        create<ast::DecoratedVariable>(create<ast::Variable>(
-            Source{}, "custom_vertex_index", ast::StorageClass::kInput, &i32));
 
-    ast::VariableDecorationList decorations;
-    decorations.push_back(
-        create<ast::BuiltinDecoration>(ast::Builtin::kVertexIdx, Source{}));
+  mod()->AddGlobalVariable(create<ast::Variable>(
+      Source{},                   // source
+      "custom_vertex_index",      // name
+      ast::StorageClass::kInput,  // storage_class
+      &i32,                       // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kVertexIdx, Source{}),
+      }));
 
-    vertex_index_var->set_decorations(decorations);
-    mod()->AddGlobalVariable(vertex_index_var);
-  }
-
-  {
-    auto* instance_index_var = create<ast::DecoratedVariable>(
-        create<ast::Variable>(Source{}, "custom_instance_index",
-                              ast::StorageClass::kInput, &i32));
-
-    ast::VariableDecorationList decorations;
-    decorations.push_back(
-        create<ast::BuiltinDecoration>(ast::Builtin::kInstanceIdx, Source{}));
-
-    instance_index_var->set_decorations(decorations);
-    mod()->AddGlobalVariable(instance_index_var);
-  }
+  mod()->AddGlobalVariable(create<ast::Variable>(
+      Source{},                   // source
+      "custom_instance_index",    // name
+      ast::StorageClass::kInput,  // storage_class
+      &i32,                       // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kInstanceIdx, Source{}),
+      }));
 
   InitTransform(
       {{{4, InputStepMode::kVertex, {{VertexFormat::kF32, 0, 0}}},
@@ -464,7 +468,7 @@
     private
     __f32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -472,7 +476,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{instance_idx}
     }
@@ -480,7 +484,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{4}
@@ -489,7 +493,7 @@
     storage_buffer
     __struct_TintVertexData
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{1}
       SetDecoration{4}
@@ -605,7 +609,7 @@
     private
     __array__f32_4
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -613,7 +617,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{4}
@@ -796,7 +800,7 @@
     private
     __array__f32_4
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BuiltinDecoration{vertex_idx}
     }
@@ -804,7 +808,7 @@
     in
     __i32
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{0}
       SetDecoration{4}
@@ -813,7 +817,7 @@
     storage_buffer
     __struct_TintVertexData
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{1}
       SetDecoration{4}
@@ -822,7 +826,7 @@
     storage_buffer
     __struct_TintVertexData
   }
-  DecoratedVariable{
+  Variable{
     Decorations{
       BindingDecoration{2}
       SetDecoration{4}
diff --git a/src/type_determiner_test.cc b/src/type_determiner_test.cc
index 9f01813..c798986 100644
--- a/src/type_determiner_test.cc
+++ b/src/type_determiner_test.cc
@@ -390,10 +390,15 @@
 
 TEST_F(TypeDeterminerTest, Stmt_VariableDecl) {
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "my_var",                  // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
   auto* init = var->constructor();
 
   ast::VariableDeclStatement decl(var);
@@ -405,10 +410,15 @@
 
 TEST_F(TypeDeterminerTest, Stmt_VariableDecl_ModuleScope) {
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "my_var",                  // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
   auto* init = var->constructor();
 
   mod->AddGlobalVariable(var);
@@ -433,8 +443,14 @@
 
   auto* idx = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 2));
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kFunction, &ary);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &ary,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -458,8 +474,14 @@
 
   auto* idx = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 2));
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kFunction, &aary);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &aary,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -482,9 +504,14 @@
 
   auto* idx = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 2));
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kFunction, &ary);
-  var->set_is_const(true);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &ary,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -506,7 +533,13 @@
   auto* idx = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 2));
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &mat);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -533,7 +566,13 @@
   auto* idx2 = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 1));
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &mat);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -560,7 +599,13 @@
   auto* idx = create<ast::ScalarConstructorExpression>(
       create<ast::SintLiteral>(&i32, 2));
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &vec);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -581,7 +626,8 @@
   ast::BitcastExpression bitcast(&f32,
                                  create<ast::IdentifierExpression>("name"));
 
-  ast::Variable v(Source{}, "name", ast::StorageClass::kPrivate, &f32);
+  ast::Variable v(Source{}, "name", ast::StorageClass::kPrivate, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
   td()->RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(td()->DetermineResultType(&bitcast));
@@ -659,7 +705,8 @@
   params.push_back(create<ast::IdentifierExpression>("name"));
   ast::TypeConstructorExpression cast(&f32, params);
 
-  ast::Variable v(Source{}, "name", ast::StorageClass::kPrivate, &f32);
+  ast::Variable v(Source{}, "name", ast::StorageClass::kPrivate, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
   td()->RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(td()->DetermineResultType(&cast));
@@ -701,7 +748,13 @@
 TEST_F(TypeDeterminerTest, Expr_Identifier_GlobalVariable) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -719,10 +772,14 @@
 
 TEST_F(TypeDeterminerTest, Expr_Identifier_GlobalConstant) {
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
-  var->set_is_const(true);
-  mod->AddGlobalVariable(var);
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "my_var",                         // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &f32,                             // type
+                            true,                             // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   // Register the global
   EXPECT_TRUE(td()->Determine());
@@ -739,8 +796,13 @@
   auto* my_var = create<ast::IdentifierExpression>("my_var");
 
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
-  var->set_is_const(true);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -762,8 +824,14 @@
   auto* my_var = create<ast::IdentifierExpression>("my_var");
 
   auto* body = create<ast::BlockStatement>();
-  body->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "my_var", ast::StorageClass::kNone, &f32)));
+  body->append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "my_var",                          // name
+                            ast::StorageClass::kNone,          // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
 
   body->append(create<ast::AssignmentStatement>(
       my_var, create<ast::IdentifierExpression>("my_var")));
@@ -788,8 +856,14 @@
   auto* my_var = create<ast::IdentifierExpression>("my_var");
 
   auto* body = create<ast::BlockStatement>();
-  body->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "my_var", ast::StorageClass::kNone, &ptr)));
+  body->append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "my_var",                          // name
+                            ast::StorageClass::kNone,          // storage_class
+                            &ptr,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
 
   body->append(create<ast::AssignmentStatement>(
       my_var, create<ast::IdentifierExpression>("my_var")));
@@ -833,16 +907,46 @@
 TEST_F(TypeDeterminerTest, Function_RegisterInputOutputVariables) {
   ast::type::F32 f32;
 
-  auto* in_var = create<ast::Variable>(Source{}, "in_var",
-                                       ast::StorageClass::kInput, &f32);
-  auto* out_var = create<ast::Variable>(Source{}, "out_var",
-                                        ast::StorageClass::kOutput, &f32);
-  auto* sb_var = create<ast::Variable>(Source{}, "sb_var",
-                                       ast::StorageClass::kStorageBuffer, &f32);
-  auto* wg_var = create<ast::Variable>(Source{}, "wg_var",
-                                       ast::StorageClass::kWorkgroup, &f32);
-  auto* priv_var = create<ast::Variable>(Source{}, "priv_var",
-                                         ast::StorageClass::kPrivate, &f32);
+  auto* in_var =
+      create<ast::Variable>(Source{},                        // source
+                            "in_var",                        // name
+                            ast::StorageClass::kInput,       // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* out_var =
+      create<ast::Variable>(Source{},                        // source
+                            "out_var",                       // name
+                            ast::StorageClass::kOutput,      // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* sb_var =
+      create<ast::Variable>(Source{},                           // source
+                            "sb_var",                           // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &f32,                               // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
+  auto* wg_var =
+      create<ast::Variable>(Source{},                        // source
+                            "wg_var",                        // name
+                            ast::StorageClass::kWorkgroup,   // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* priv_var =
+      create<ast::Variable>(Source{},                        // source
+                            "priv_var",                      // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   mod->AddGlobalVariable(in_var);
   mod->AddGlobalVariable(out_var);
@@ -884,16 +988,46 @@
 TEST_F(TypeDeterminerTest, Function_RegisterInputOutputVariables_SubFunction) {
   ast::type::F32 f32;
 
-  auto* in_var = create<ast::Variable>(Source{}, "in_var",
-                                       ast::StorageClass::kInput, &f32);
-  auto* out_var = create<ast::Variable>(Source{}, "out_var",
-                                        ast::StorageClass::kOutput, &f32);
-  auto* sb_var = create<ast::Variable>(Source{}, "sb_var",
-                                       ast::StorageClass::kStorageBuffer, &f32);
-  auto* wg_var = create<ast::Variable>(Source{}, "wg_var",
-                                       ast::StorageClass::kWorkgroup, &f32);
-  auto* priv_var = create<ast::Variable>(Source{}, "priv_var",
-                                         ast::StorageClass::kPrivate, &f32);
+  auto* in_var =
+      create<ast::Variable>(Source{},                        // source
+                            "in_var",                        // name
+                            ast::StorageClass::kInput,       // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* out_var =
+      create<ast::Variable>(Source{},                        // source
+                            "out_var",                       // name
+                            ast::StorageClass::kOutput,      // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* sb_var =
+      create<ast::Variable>(Source{},                           // source
+                            "sb_var",                           // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &f32,                               // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
+  auto* wg_var =
+      create<ast::Variable>(Source{},                        // source
+                            "wg_var",                        // name
+                            ast::StorageClass::kWorkgroup,   // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* priv_var =
+      create<ast::Variable>(Source{},                        // source
+                            "priv_var",                      // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   mod->AddGlobalVariable(in_var);
   mod->AddGlobalVariable(out_var);
@@ -945,8 +1079,14 @@
 TEST_F(TypeDeterminerTest, Function_NotRegisterFunctionVariable) {
   ast::type::F32 f32;
 
-  auto* var = create<ast::Variable>(Source{}, "in_var",
-                                    ast::StorageClass::kFunction, &f32);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "in_var",                        // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -961,7 +1101,8 @@
 
   mod->AddFunction(func);
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kFunction, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kFunction, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
   td()->RegisterVariableForTesting(&v);
 
   // Register the function
@@ -983,8 +1124,14 @@
 
   ast::type::Struct st("S", strct);
 
-  auto* var = create<ast::Variable>(Source{}, "my_struct",
-                                    ast::StorageClass::kNone, &st);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_struct",                     // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &st,                             // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   mod->AddGlobalVariable(var);
 
@@ -1017,8 +1164,14 @@
   auto st = std::make_unique<ast::type::Struct>("alias", strct);
   ast::type::Alias alias("alias", st.get());
 
-  auto* var = create<ast::Variable>(Source{}, "my_struct",
-                                    ast::StorageClass::kNone, &alias);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_struct",                     // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &alias,                          // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   mod->AddGlobalVariable(var);
 
@@ -1041,8 +1194,14 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_vec",
-                                    ast::StorageClass::kNone, &vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_vec",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1064,8 +1223,14 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_vec",
-                                    ast::StorageClass::kNone, &vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_vec",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1130,7 +1295,13 @@
   ast::type::Struct stA("A", strctA);
 
   auto* var =
-      create<ast::Variable>(Source{}, "c", ast::StorageClass::kNone, &stA);
+      create<ast::Variable>(Source{},                        // source
+                            "c",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &stA,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1165,7 +1336,13 @@
   ast::type::I32 i32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1186,7 +1363,13 @@
   ast::type::Vector vec3(&i32, 3);
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1222,8 +1405,14 @@
 
   ast::type::Bool bool_type;
 
-  auto* var = create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone,
-                                    &bool_type);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &bool_type,                      // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1244,7 +1433,13 @@
   ast::type::Vector vec3(&bool_type, 3);
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1274,7 +1469,13 @@
   ast::type::I32 i32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1295,7 +1496,13 @@
   ast::type::Vector vec3(&i32, 3);
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1326,7 +1533,13 @@
   ast::type::I32 i32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kNone, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "val",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1346,9 +1559,21 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* scalar =
-      create<ast::Variable>(Source{}, "scalar", ast::StorageClass::kNone, &f32);
-  auto* vector = create<ast::Variable>(Source{}, "vector",
-                                       ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "scalar",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* vector =
+      create<ast::Variable>(Source{},                        // source
+                            "vector",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(scalar);
   mod->AddGlobalVariable(vector);
 
@@ -1374,9 +1599,21 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* scalar =
-      create<ast::Variable>(Source{}, "scalar", ast::StorageClass::kNone, &f32);
-  auto* vector = create<ast::Variable>(Source{}, "vector",
-                                       ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "scalar",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* vector =
+      create<ast::Variable>(Source{},                        // source
+                            "vector",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(scalar);
   mod->AddGlobalVariable(vector);
 
@@ -1401,8 +1638,14 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  auto* vector = create<ast::Variable>(Source{}, "vector",
-                                       ast::StorageClass::kNone, &vec3);
+  auto* vector =
+      create<ast::Variable>(Source{},                        // source
+                            "vector",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(vector);
 
   // Register the global
@@ -1427,9 +1670,21 @@
   ast::type::Matrix mat3x2(&f32, 3, 2);
 
   auto* scalar =
-      create<ast::Variable>(Source{}, "scalar", ast::StorageClass::kNone, &f32);
-  auto* matrix = create<ast::Variable>(Source{}, "matrix",
-                                       ast::StorageClass::kNone, &mat3x2);
+      create<ast::Variable>(Source{},                        // source
+                            "scalar",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* matrix =
+      create<ast::Variable>(Source{},                        // source
+                            "matrix",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat3x2,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(scalar);
   mod->AddGlobalVariable(matrix);
 
@@ -1455,9 +1710,21 @@
   ast::type::Matrix mat3x2(&f32, 3, 2);
 
   auto* scalar =
-      create<ast::Variable>(Source{}, "scalar", ast::StorageClass::kNone, &f32);
-  auto* matrix = create<ast::Variable>(Source{}, "matrix",
-                                       ast::StorageClass::kNone, &mat3x2);
+      create<ast::Variable>(Source{},                        // source
+                            "scalar",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* matrix =
+      create<ast::Variable>(Source{},                        // source
+                            "matrix",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat3x2,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(scalar);
   mod->AddGlobalVariable(matrix);
 
@@ -1483,10 +1750,22 @@
   ast::type::Vector vec3(&f32, 2);
   ast::type::Matrix mat3x2(&f32, 3, 2);
 
-  auto* vector = create<ast::Variable>(Source{}, "vector",
-                                       ast::StorageClass::kNone, &vec3);
-  auto* matrix = create<ast::Variable>(Source{}, "matrix",
-                                       ast::StorageClass::kNone, &mat3x2);
+  auto* vector =
+      create<ast::Variable>(Source{},                        // source
+                            "vector",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* matrix =
+      create<ast::Variable>(Source{},                        // source
+                            "matrix",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat3x2,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(vector);
   mod->AddGlobalVariable(matrix);
 
@@ -1512,10 +1791,22 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3x2(&f32, 3, 2);
 
-  auto* vector = create<ast::Variable>(Source{}, "vector",
-                                       ast::StorageClass::kNone, &vec3);
-  auto* matrix = create<ast::Variable>(Source{}, "matrix",
-                                       ast::StorageClass::kNone, &mat3x2);
+  auto* vector =
+      create<ast::Variable>(Source{},                        // source
+                            "vector",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* matrix =
+      create<ast::Variable>(Source{},                        // source
+                            "matrix",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat3x2,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(vector);
   mod->AddGlobalVariable(matrix);
 
@@ -1541,10 +1832,22 @@
   ast::type::Matrix mat4x3(&f32, 4, 3);
   ast::type::Matrix mat3x4(&f32, 3, 4);
 
-  auto* matrix1 = create<ast::Variable>(Source{}, "mat4x3",
-                                        ast::StorageClass::kNone, &mat4x3);
-  auto* matrix2 = create<ast::Variable>(Source{}, "mat3x4",
-                                        ast::StorageClass::kNone, &mat3x4);
+  auto* matrix1 =
+      create<ast::Variable>(Source{},                        // source
+                            "mat4x3",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat4x3,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* matrix2 =
+      create<ast::Variable>(Source{},                        // source
+                            "mat3x4",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat3x4,                         // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(matrix1);
   mod->AddGlobalVariable(matrix2);
 
@@ -1572,7 +1875,13 @@
   ast::type::F32 f32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "ident", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "ident",                         // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1596,7 +1905,13 @@
   ast::type::Vector vec4(&f32, 4);
 
   auto* var =
-      create<ast::Variable>(Source{}, "ident", ast::StorageClass::kNone, &vec4);
+      create<ast::Variable>(Source{},                        // source
+                            "ident",                         // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec4,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -1640,10 +1955,22 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* var1 = create<ast::Variable>(Source{}, "ident1",
-                                     ast::StorageClass::kNone, &vec4);
-  auto* var2 = create<ast::Variable>(Source{}, "ident2",
-                                     ast::StorageClass::kNone, &vec4);
+  auto* var1 =
+      create<ast::Variable>(Source{},                        // source
+                            "ident1",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec4,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* var2 =
+      create<ast::Variable>(Source{},                        // source
+                            "ident2",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec4,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var1);
   mod->AddGlobalVariable(var2);
 
@@ -1678,8 +2005,14 @@
   ast::type::Bool bool_type;
   ast::type::Vector vec3(&bool_type, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kNone, &vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -1706,8 +2039,14 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kNone, &vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -1735,7 +2074,13 @@
   ast::type::F32 f32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -1757,7 +2102,13 @@
   ast::type::F32 f32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -1776,7 +2127,13 @@
   ast::type::F32 f32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "my_var", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -1846,7 +2203,13 @@
                       ast::type::Type* type,
                       ast::ExpressionList* call_params) {
     auto* var =
-        create<ast::Variable>(Source{}, name, ast::StorageClass::kNone, type);
+        create<ast::Variable>(Source{},                        // source
+                              name,                            // name
+                              ast::StorageClass::kNone,        // storage_class
+                              type,                            // type
+                              false,                           // is_const
+                              nullptr,                         // constructor
+                              ast::VariableDecorationList{});  // decorations
     mod->AddGlobalVariable(var);
     call_params->push_back(create<ast::IdentifierExpression>(name));
   }
@@ -1998,8 +2361,14 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kNone, &vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -2022,10 +2391,22 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Vector bool_vec3(&bool_type, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "my_var",
-                                    ast::StorageClass::kNone, &vec3);
-  auto* bool_var = create<ast::Variable>(Source{}, "bool_var",
-                                         ast::StorageClass::kNone, &bool_vec3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "my_var",                        // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* bool_var =
+      create<ast::Variable>(Source{},                        // source
+                            "bool_var",                      // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &bool_vec3,                      // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
   mod->AddGlobalVariable(bool_var);
 
@@ -2054,7 +2435,13 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -2075,7 +2462,13 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   ast::ExpressionList call_params;
@@ -2100,9 +2493,21 @@
   ast::type::Vector vec2(&f32, 2);
 
   auto* var1 =
-      create<ast::Variable>(Source{}, "v3", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "v3",                            // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* var2 =
-      create<ast::Variable>(Source{}, "v2", ast::StorageClass::kNone, &vec2);
+      create<ast::Variable>(Source{},                        // source
+                            "v2",                            // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec2,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var1);
   mod->AddGlobalVariable(var2);
 
@@ -2132,7 +2537,13 @@
   ast::type::Vector vec2(&f32, 2);
 
   auto* var2 =
-      create<ast::Variable>(Source{}, "v2", ast::StorageClass::kNone, &vec2);
+      create<ast::Variable>(Source{},                        // source
+                            "v2",                            // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec2,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var2);
 
   ast::ExpressionList call_params;
@@ -2153,7 +2564,13 @@
   ast::type::Vector vec2(&f32, 2);
 
   auto* var2 =
-      create<ast::Variable>(Source{}, "v2", ast::StorageClass::kNone, &vec2);
+      create<ast::Variable>(Source{},                        // source
+                            "v2",                            // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec2,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var2);
 
   ast::ExpressionList call_params;
@@ -2179,7 +2596,13 @@
   ast::type::Vector vec4(&f32, 4);
 
   auto* var =
-      create<ast::Variable>(Source{}, "ident", ast::StorageClass::kNone, &vec4);
+      create<ast::Variable>(Source{},                        // source
+                            "ident",                         // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec4,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -2202,7 +2625,13 @@
   ast::type::I32 i32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(var);
 
   auto* body = create<ast::BlockStatement>();
@@ -2220,8 +2649,13 @@
   ast::type::I32 i32;
 
   auto* var =
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &i32);
-  var->set_is_const(true);
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(var);
 
   auto* body = create<ast::BlockStatement>();
@@ -2238,8 +2672,14 @@
 TEST_F(TypeDeterminerTest, StorageClass_NonFunctionClassError) {
   ast::type::I32 i32;
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kWorkgroup, &i32);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kWorkgroup,   // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* stmt = create<ast::VariableDeclStatement>(var);
 
   auto* body = create<ast::BlockStatement>();
@@ -4296,8 +4736,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kFunction, &mat);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -4322,8 +4768,14 @@
 
   ast::type::F32 f32;
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kFunction, &f32);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -4359,8 +4811,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kFunction, &mat);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   mod->AddGlobalVariable(var);
 
   // Register the global
@@ -4450,16 +4908,46 @@
   mod->AddFunction(ep_1);
   mod->AddFunction(ep_2);
 
-  mod->AddGlobalVariable(create<ast::Variable>(
-      Source{}, "first", ast::StorageClass::kPrivate, &f32));
-  mod->AddGlobalVariable(create<ast::Variable>(
-      Source{}, "second", ast::StorageClass::kPrivate, &f32));
-  mod->AddGlobalVariable(create<ast::Variable>(
-      Source{}, "call_a", ast::StorageClass::kPrivate, &f32));
-  mod->AddGlobalVariable(create<ast::Variable>(
-      Source{}, "call_b", ast::StorageClass::kPrivate, &f32));
-  mod->AddGlobalVariable(create<ast::Variable>(
-      Source{}, "call_c", ast::StorageClass::kPrivate, &f32));
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "first",                          // name
+                            ast::StorageClass::kPrivate,      // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "second",                         // name
+                            ast::StorageClass::kPrivate,      // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "call_a",                         // name
+                            ast::StorageClass::kPrivate,      // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "call_b",                         // name
+                            ast::StorageClass::kPrivate,      // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
+  mod->AddGlobalVariable(
+      create<ast::Variable>(Source{},                         // source
+                            "call_c",                         // name
+                            ast::StorageClass::kPrivate,      // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   // Register the functions and calculate the callers
   ASSERT_TRUE(td()->Determine()) << td()->error();
diff --git a/src/validator/validator_control_block_test.cc b/src/validator/validator_control_block_test.cc
index 08f59b9..b4c5990 100644
--- a/src/validator/validator_control_block_test.cc
+++ b/src/validator/validator_control_block_test.cc
@@ -43,10 +43,15 @@
   //   default: {}
   // }
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&f32, 3.14f)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&f32, 3.14f)),  // constructor
+      ast::VariableDecorationList{});              // decorations
 
   auto* cond =
       create<ast::IdentifierExpression>(Source{Source::Location{12, 34}}, "a");
@@ -72,10 +77,15 @@
   //   case 1: {}
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* cond = create<ast::IdentifierExpression>("a");
   ast::CaseSelectorList csl;
@@ -104,10 +114,15 @@
   //   default: {}
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::CaseStatementList switch_body;
   auto* cond = create<ast::IdentifierExpression>("a");
@@ -148,10 +163,15 @@
   // }
   ast::type::U32 u32;
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::CaseStatementList switch_body;
   auto* cond = create<ast::IdentifierExpression>("a");
@@ -185,10 +205,15 @@
   // }
   ast::type::U32 u32;
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &u32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::UintLiteral>(&u32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &u32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::UintLiteral>(&u32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::CaseStatementList switch_body;
   auto* cond = create<ast::IdentifierExpression>("a");
@@ -221,10 +246,15 @@
   //   default: {}
   // }
   ast::type::U32 u32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &u32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::UintLiteral>(&u32, 3)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &u32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::UintLiteral>(&u32, 3)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::CaseStatementList switch_body;
   auto* cond = create<ast::IdentifierExpression>("a");
@@ -263,10 +293,15 @@
   //   default: {}
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::CaseStatementList switch_body;
   auto* cond = create<ast::IdentifierExpression>("a");
@@ -305,10 +340,15 @@
   //   default: { fallthrough; }
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* cond = create<ast::IdentifierExpression>("a");
   ast::CaseSelectorList default_csl;
@@ -336,10 +376,15 @@
   //   case 5: {}
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* cond = create<ast::IdentifierExpression>("a");
   ast::CaseSelectorList default_csl;
@@ -370,10 +415,15 @@
   ast::type::U32 u32;
   ast::type::Alias my_int{"MyInt", &u32};
 
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &my_int);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&u32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &my_int,                   // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&u32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* cond = create<ast::IdentifierExpression>("a");
   ast::CaseSelectorList default_csl;
diff --git a/src/validator/validator_function_test.cc b/src/validator/validator_function_test.cc
index 2327220..c335c22 100644
--- a/src/validator/validator_function_test.cc
+++ b/src/validator/validator_function_test.cc
@@ -39,10 +39,15 @@
   // [[stage(vertex)]]
   // fn func -> void { var a:i32 = 2; }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::VariableList params;
   ast::type::Void void_type;
@@ -81,10 +86,15 @@
   // fn func -> int { var a:i32 = 2; }
 
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   ast::VariableList params;
   ast::type::Void void_type;
@@ -239,13 +249,18 @@
 TEST_F(ValidateFunctionTest, RecursionIsNotAllowedExpr_Fail) {
   // fn func() -> i32 {var a: i32 = func(); return 2; }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
   ast::ExpressionList call_params;
   auto* call_expr = create<ast::CallExpression>(
       Source{Source::Location{12, 34}},
       create<ast::IdentifierExpression>("func"), call_params);
-  var->set_constructor(call_expr);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            call_expr,                       // constructor
+                            ast::VariableDecorationList{});  // decorations
   ast::VariableList params0;
   auto* body0 = create<ast::BlockStatement>();
   body0->append(create<ast::VariableDeclStatement>(var));
@@ -292,7 +307,13 @@
   ast::type::Void void_type;
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &i32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(Source{}));
   auto* func = create<ast::Function>(
diff --git a/src/validator/validator_test.cc b/src/validator/validator_test.cc
index 8c95501..d993b1e 100644
--- a/src/validator/validator_test.cc
+++ b/src/validator/validator_test.cc
@@ -115,10 +115,15 @@
   // var a :i32 = 2;
   // a = 2
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
@@ -140,10 +145,16 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
+
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 2.3f));
@@ -167,10 +178,15 @@
   //  a = 2
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
@@ -196,10 +212,15 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 2.3f));
@@ -223,10 +244,14 @@
 TEST_F(ValidatorTest, GlobalVariableWithStorageClass_Pass) {
   // var<in> gloabl_var: f32;
   ast::type::F32 f32;
-  auto* global_var =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var",
-                            ast::StorageClass::kInput, &f32);
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(
+      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
+                            "global_var",                      // name
+                            ast::StorageClass::kInput,         // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{}));   // decorations
   EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables()))
       << v()->error();
 }
@@ -234,24 +259,31 @@
 TEST_F(ValidatorTest, GlobalVariableNoStorageClass_Fail) {
   // var gloabl_var: f32;
   ast::type::F32 f32;
-  auto* global_var =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var",
-                            ast::StorageClass::kNone, &f32);
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(
+      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
+                            "global_var",                      // name
+                            ast::StorageClass::kNone,          // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{}));   // decorations
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_FALSE(v()->Validate(mod()));
   EXPECT_EQ(v()->error(),
             "12:34 v-0022: global variables must have a storage class");
 }
+
 TEST_F(ValidatorTest, GlobalConstantWithStorageClass_Fail) {
   // const<in> gloabl_var: f32;
   ast::type::F32 f32;
-  auto* global_var =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var",
-                            ast::StorageClass::kInput, &f32);
-  global_var->set_is_const(true);
-
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(
+      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
+                            "global_var",                      // name
+                            ast::StorageClass::kInput,         // storage_class
+                            &f32,                              // type
+                            true,                              // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{}));   // decorations
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_FALSE(v()->Validate(mod()));
   EXPECT_EQ(
@@ -262,12 +294,14 @@
 TEST_F(ValidatorTest, GlobalConstNoStorageClass_Pass) {
   // const gloabl_var: f32;
   ast::type::F32 f32;
-  auto* global_var =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var",
-                            ast::StorageClass::kNone, &f32);
-  global_var->set_is_const(true);
-
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(
+      create<ast::Variable>(Source{Source::Location{12, 34}},  // source
+                            "global_var",                      // name
+                            ast::StorageClass::kNone,          // storage_class
+                            &f32,                              // type
+                            true,                              // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{}));   // decorations
   EXPECT_TRUE(td()->Determine()) << td()->error();
   EXPECT_FALSE(v()->Validate(mod())) << v()->error();
 }
@@ -278,11 +312,15 @@
   //   not_global_var = 3.14f;
   // }
   ast::type::F32 f32;
-  auto* global_var = create<ast::Variable>(Source{}, "global_var",
-                                           ast::StorageClass::kPrivate, &f32);
-  global_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.1)));
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(create<ast::Variable>(
+      Source{},                     // source
+      "global_var",                 // name
+      ast::StorageClass::kPrivate,  // storage_class
+      &f32,                         // type
+      false,                        // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.1)),  // constructor
+      ast::VariableDecorationList{}));            // decorations
 
   auto* lhs = create<ast::IdentifierExpression>(
       Source{Source::Location{12, 34}}, "not_global_var");
@@ -311,11 +349,15 @@
   ast::type::F32 f32;
   ast::type::Void void_type;
 
-  auto* global_var = create<ast::Variable>(Source{}, "global_var",
-                                           ast::StorageClass::kPrivate, &f32);
-  global_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.1)));
-  mod()->AddGlobalVariable(global_var);
+  mod()->AddGlobalVariable(create<ast::Variable>(
+      Source{},                     // source
+      "global_var",                 // name
+      ast::StorageClass::kPrivate,  // storage_class
+      &f32,                         // type
+      false,                        // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.1)),  // constructor
+      ast::VariableDecorationList{}));            // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("global_var");
   auto* rhs = create<ast::ScalarConstructorExpression>(
@@ -344,10 +386,15 @@
   //   a = 3.14;
   // }
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
@@ -379,10 +426,15 @@
   //   if (true) { a = 3.14; }
   // }
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   auto* lhs =
       create<ast::IdentifierExpression>(Source{Source::Location{12, 34}}, "a");
@@ -411,17 +463,26 @@
   // var global_var1 : i32 = 0;
   ast::type::F32 f32;
   ast::type::I32 i32;
-  auto* var0 = create<ast::Variable>(Source{}, "global_var0",
-                                     ast::StorageClass::kPrivate, &f32);
-  var0->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 0.1)));
+  auto* var0 = create<ast::Variable>(
+      Source{},                     // source
+      "global_var0",                // name
+      ast::StorageClass::kPrivate,  // storage_class
+      &f32,                         // type
+      false,                        // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 0.1)),  // constructor
+      ast::VariableDecorationList{});             // decorations
   mod()->AddGlobalVariable(var0);
 
-  auto* var1 =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var1",
-                            ast::StorageClass::kPrivate, &f32);
-  var1->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 0)));
+  auto* var1 = create<ast::Variable>(
+      Source{Source::Location{12, 34}},  // source
+      "global_var1",                     // name
+      ast::StorageClass::kPrivate,       // storage_class
+      &f32,                              // type
+      false,                             // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 0)),  // constructor
+      ast::VariableDecorationList{});          // decorations
   mod()->AddGlobalVariable(var1);
 
   EXPECT_TRUE(v()->ValidateGlobalVariables(mod()->global_variables()))
@@ -433,17 +494,26 @@
   // var global_var : i32 = 0;
   ast::type::F32 f32;
   ast::type::I32 i32;
-  auto* var0 = create<ast::Variable>(Source{}, "global_var",
-                                     ast::StorageClass::kPrivate, &f32);
-  var0->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 0.1)));
+  auto* var0 = create<ast::Variable>(
+      Source{},                     // source
+      "global_var",                 // name
+      ast::StorageClass::kPrivate,  // storage_class
+      &f32,                         // type
+      false,                        // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 0.1)),  // constructor
+      ast::VariableDecorationList{});             // decorations
   mod()->AddGlobalVariable(var0);
 
-  auto* var1 =
-      create<ast::Variable>(Source{Source::Location{12, 34}}, "global_var",
-                            ast::StorageClass::kPrivate, &f32);
-  var1->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 0)));
+  auto* var1 = create<ast::Variable>(
+      Source{Source::Location{12, 34}},  // source
+      "global_var",                      // name
+      ast::StorageClass::kPrivate,       // storage_class
+      &f32,                              // type
+      false,                             // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 0)),  // constructor
+      ast::VariableDecorationList{});          // decorations
   mod()->AddGlobalVariable(var1);
 
   EXPECT_FALSE(v()->ValidateGlobalVariables(mod()->global_variables()));
@@ -457,11 +527,15 @@
   //  a = 2
   // }
   ast::type::I32 i32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
-  var->set_is_const(true);
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      true,                      // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::ScalarConstructorExpression>(
@@ -489,16 +563,26 @@
 
   ast::type::Void void_type;
   ast::type::F32 f32;
-  auto* global_var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &f32);
-  global_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.1)));
+  auto* global_var = create<ast::Variable>(
+      Source{},                     // source
+      "a",                          // name
+      ast::StorageClass::kPrivate,  // storage_class
+      &f32,                         // type
+      false,                        // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.1)),  // constructor
+      ast::VariableDecorationList{});             // decorations
   mod()->AddGlobalVariable(global_var);
 
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
   ast::VariableList params;
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(
@@ -522,15 +606,25 @@
   ast::type::Void void_type;
   ast::type::I32 i32;
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &i32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::SintLiteral>(&i32, 2)),  // constructor
+      ast::VariableDecorationList{});          // decorations
 
-  auto* var_a_float =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var_a_float->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 0.1)));
+  auto* var_a_float = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 0.1)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   ast::VariableList params;
   auto* body = create<ast::BlockStatement>();
@@ -554,10 +648,15 @@
   // var a : f32 = 3.14;
   // }
   ast::type::F32 f32;
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
@@ -565,10 +664,15 @@
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
 
-  auto* var_a_float =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var_a_float->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 3.14)));
+  auto* var_a_float = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 3.14)),  // constructor
+      ast::VariableDecorationList{});              // decorations
 
   auto* outer_body = create<ast::BlockStatement>();
   outer_body->append(
@@ -588,15 +692,25 @@
   // if (true) { var a : f32 = 2.0; }
   // }
   ast::type::F32 f32;
-  auto* var_a_float =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var_a_float->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 3.14)));
+  auto* var_a_float = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 3.14)),  // constructor
+      ast::VariableDecorationList{});              // decorations
 
-  auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   ast::type::Bool bool_type;
   auto* cond = create<ast::ScalarConstructorExpression>(
@@ -620,15 +734,25 @@
   // func1 { var a : f32 = 3.0; return; }
   ast::type::F32 f32;
   ast::type::Void void_type;
-  auto* var0 =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var0->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
+  auto* var0 = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
-  auto* var1 = create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone,
-                                     &void_type);
-  var1->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 1.0)));
+  auto* var1 = create<ast::Variable>(
+      Source{},                  // source
+      "a",                       // name
+      ast::StorageClass::kNone,  // storage_class
+      &void_type,                // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 1.0)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   ast::VariableList params0;
   auto* body0 = create<ast::BlockStatement>();
@@ -663,7 +787,13 @@
   // }
   ast::type::I32 i32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   td()->RegisterVariableForTesting(var);
   auto* lhs = create<ast::IdentifierExpression>("a");
diff --git a/src/validator/validator_type_test.cc b/src/validator/validator_type_test.cc
index 2195c92..2fbaeff 100644
--- a/src/validator/validator_type_test.cc
+++ b/src/validator/validator_type_test.cc
@@ -194,7 +194,13 @@
   ast::type::Array array(&i32, 0, ast::ArrayDecorationList{});
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &array);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &array,                          // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   ast::VariableList params;
   ast::type::Void void_type;
   auto* body = create<ast::BlockStatement>();
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index ae7baae..c52c8df 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -27,7 +27,7 @@
 #include "src/ast/call_expression.h"
 #include "src/ast/call_statement.h"
 #include "src/ast/case_statement.h"
-#include "src/ast/decorated_variable.h"
+#include "src/ast/constant_id_decoration.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/fallthrough_statement.h"
 #include "src/ast/float_literal.h"
@@ -56,6 +56,7 @@
 #include "src/ast/type/void_type.h"
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/writer/append_vector.h"
 #include "src/writer/float_to_string.h"
@@ -1035,12 +1036,9 @@
 }
 
 bool GeneratorImpl::global_is_in_struct(ast::Variable* var) const {
-  if (auto* decorated = var->As<ast::DecoratedVariable>()) {
-    if (decorated->HasLocationDecoration() ||
-        decorated->HasBuiltinDecoration()) {
-      return var->storage_class() == ast::StorageClass::kInput ||
-             var->storage_class() == ast::StorageClass::kOutput;
-    }
+  if (var->HasLocationDecoration() || var->HasBuiltinDecoration()) {
+    return var->storage_class() == ast::StorageClass::kInput ||
+           var->storage_class() == ast::StorageClass::kOutput;
   }
   return false;
 }
@@ -2237,7 +2235,7 @@
   make_indent(out);
 
   // TODO(dsinclair): Handle variable decorations
-  if (var->Is<ast::DecoratedVariable>()) {
+  if (!var->decorations().empty()) {
     error_ = "Variable decorations are not handled yet";
     return false;
   }
@@ -2271,10 +2269,11 @@
                                              const ast::Variable* var) {
   make_indent(out);
 
-  auto* decorated = var->As<ast::DecoratedVariable>();
-  if (decorated != nullptr && !decorated->HasConstantIdDecoration()) {
-    error_ = "Decorated const values not valid";
-    return false;
+  for (auto* d : var->decorations()) {
+    if (!d->Is<ast::ConstantIdDecoration>()) {
+      error_ = "Decorated const values not valid";
+      return false;
+    }
   }
   if (!var->is_const()) {
     error_ = "Expected a const value";
@@ -2290,8 +2289,8 @@
     out << pre.str();
   }
 
-  if (decorated != nullptr && decorated->HasConstantIdDecoration()) {
-    auto const_id = decorated->constant_id();
+  if (var->HasConstantIdDecoration()) {
+    auto const_id = var->constant_id();
 
     out << "#ifndef WGSL_SPEC_CONSTANT_" << const_id << std::endl;
 
diff --git a/src/writer/hlsl/generator_impl_binary_test.cc b/src/writer/hlsl/generator_impl_binary_test.cc
index 1a7310a..20654eb 100644
--- a/src/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/writer/hlsl/generator_impl_binary_test.cc
@@ -62,10 +62,22 @@
 
   auto params = GetParam();
 
-  auto* left_var = create<ast::Variable>(Source{}, "left",
-                                         ast::StorageClass::kFunction, &f32);
-  auto* right_var = create<ast::Variable>(Source{}, "right",
-                                          ast::StorageClass::kFunction, &f32);
+  auto* left_var =
+      create<ast::Variable>(Source{},                        // source
+                            "left",                          // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* right_var =
+      create<ast::Variable>(Source{},                        // source
+                            "right",                         // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* left = create<ast::IdentifierExpression>("left");
   auto* right = create<ast::IdentifierExpression>("right");
@@ -84,10 +96,22 @@
 
   auto params = GetParam();
 
-  auto* left_var = create<ast::Variable>(Source{}, "left",
-                                         ast::StorageClass::kFunction, &u32);
-  auto* right_var = create<ast::Variable>(Source{}, "right",
-                                          ast::StorageClass::kFunction, &u32);
+  auto* left_var =
+      create<ast::Variable>(Source{},                        // source
+                            "left",                          // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &u32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* right_var =
+      create<ast::Variable>(Source{},                        // source
+                            "right",                         // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &u32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* left = create<ast::IdentifierExpression>("left");
   auto* right = create<ast::IdentifierExpression>("right");
@@ -106,10 +130,22 @@
 
   auto params = GetParam();
 
-  auto* left_var = create<ast::Variable>(Source{}, "left",
-                                         ast::StorageClass::kFunction, &i32);
-  auto* right_var = create<ast::Variable>(Source{}, "right",
-                                          ast::StorageClass::kFunction, &i32);
+  auto* left_var =
+      create<ast::Variable>(Source{},                        // source
+                            "left",                          // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* right_var =
+      create<ast::Variable>(Source{},                        // source
+                            "right",                         // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* left = create<ast::IdentifierExpression>("left");
   auto* right = create<ast::IdentifierExpression>("right");
@@ -199,8 +235,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
   auto* rhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.f));
@@ -218,8 +260,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.f));
   auto* rhs = create<ast::IdentifierExpression>("mat");
@@ -238,8 +286,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
 
   ast::ExpressionList vals;
@@ -265,8 +319,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList vals;
   vals.push_back(create<ast::ScalarConstructorExpression>(
@@ -293,8 +353,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
   auto* rhs = create<ast::IdentifierExpression>("mat");
 
@@ -489,11 +555,17 @@
   auto* c = create<ast::IdentifierExpression>("c");
   auto* d = create<ast::IdentifierExpression>("d");
 
-  auto* var = create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction,
-                                    &bool_type);
-  var->set_constructor(create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, b, c), d));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "a",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &bool_type,                    // type
+      false,                         // is_const
+      create<ast::BinaryExpression>(
+          ast::BinaryOp::kLogicalOr,
+          create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, b, c),
+          d),                          // constructor
+      ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement expr(var);
 
diff --git a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
index 96b9044..57c8553 100644
--- a/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/hlsl/generator_impl_function_entry_point_data_test.cc
@@ -16,7 +16,6 @@
 #include <unordered_set>
 
 #include "src/ast/assignment_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/member_accessor_expression.h"
@@ -52,13 +51,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -108,13 +123,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -165,13 +196,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -222,13 +269,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -275,17 +338,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(0, Source{}));
-  foo_var->set_decorations(decos);
-
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -327,17 +402,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(0, Source{}));
-  foo_var->set_decorations(decos);
-
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -386,15 +473,29 @@
   ast::type::Void void_type;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index a20f2f4..95543a7 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -16,7 +16,6 @@
 #include "src/ast/binary_expression.h"
 #include "src/ast/binding_decoration.h"
 #include "src/ast/call_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
@@ -99,9 +98,21 @@
 
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   params.push_back(
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kNone, &i32));
+      create<ast::Variable>(Source{},                         // source
+                            "b",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &i32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   ast::type::Void void_type;
 
@@ -126,13 +137,29 @@
   ast::type::Void void_type;
   ast::type::F32 f32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -179,16 +206,29 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
-
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
@@ -237,23 +277,33 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kUniform, &vec4));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                     // source
+                            "coord",                      // name
+                            ast::StorageClass::kUniform,  // storage_class
+                            &vec4,                        // type
+                            false,                        // is_const
+                            nullptr,                      // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("x")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("x")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -294,27 +344,37 @@
 
   ast::type::Struct s("Uniforms", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "uniforms", ast::StorageClass::kUniform, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                     // source
+                            "uniforms",                   // name
+                            ast::StorageClass::kUniform,  // storage_class
+                            &s,                           // type
+                            false,                        // is_const
+                            nullptr,                      // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   mod.AddConstructedType(&s);
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
-
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
       create<ast::MemberAccessorExpression>(
-          create<ast::IdentifierExpression>("uniforms"),
-          create<ast::IdentifierExpression>("coord")),
-      create<ast::IdentifierExpression>("x")));
+          create<ast::MemberAccessorExpression>(
+              create<ast::IdentifierExpression>("uniforms"),
+              create<ast::IdentifierExpression>("coord")),
+          create<ast::IdentifierExpression>("x")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -363,23 +423,33 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("b")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("b")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -424,23 +494,33 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadOnly, &s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("b")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("b")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -485,13 +565,18 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
@@ -534,17 +619,41 @@
   ast::type::Void void_type;
   ast::type::F32 f32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
-  auto* val_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kOutput, &f32));
-  val_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* val_var =
+      create<ast::Variable>(Source{},                    // source
+                            "val",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -555,8 +664,14 @@
   mod.AddGlobalVariable(val_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::AssignmentStatement>(
@@ -622,21 +737,31 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(
-      create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}));
-  depth_var->set_decorations(decos);
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(depth_var);
 
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -690,15 +815,29 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
@@ -707,8 +846,14 @@
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::AssignmentStatement>(
@@ -771,21 +916,32 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kUniform, &vec4));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                     // source
+                            "coord",                      // name
+                            ast::StorageClass::kUniform,  // storage_class
+                            &vec4,                        // type
+                            false,                        // is_const
+                            nullptr,                      // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -801,10 +957,15 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::CallExpression>(
-      create<ast::IdentifierExpression>("sub_func"), expr));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::CallExpression>(create<ast::IdentifierExpression>("sub_func"),
+                                  expr),  // constructor
+      ast::VariableDecorationList{});     // decorations
 
   body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -841,21 +1002,32 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &vec4);
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -871,10 +1043,15 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::CallExpression>(
-      create<ast::IdentifierExpression>("sub_func"), expr));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::CallExpression>(create<ast::IdentifierExpression>("sub_func"),
+                                  expr),  // constructor
+      ast::VariableDecorationList{});     // decorations
 
   body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -909,11 +1086,17 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(bar_var);
   mod.AddGlobalVariable(bar_var);
@@ -1041,7 +1224,13 @@
 
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &ary));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &ary,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   ast::type::Void void_type;
 
@@ -1095,13 +1284,18 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* data_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(0, Source{}));
-  data_var->set_decorations(decos);
+  auto* data_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(0, Source{}),
+                            });
 
   mod.AddConstructedType(&s);
   td.RegisterVariableForTesting(data_var);
@@ -1109,11 +1303,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
@@ -1130,11 +1329,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
diff --git a/src/writer/hlsl/generator_impl_import_test.cc b/src/writer/hlsl/generator_impl_import_test.cc
index fafcd69..09d9c2d 100644
--- a/src/writer/hlsl/generator_impl_import_test.cc
+++ b/src/writer/hlsl/generator_impl_import_test.cc
@@ -268,8 +268,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kFunction, &mat);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList params;
   params.push_back(create<ast::IdentifierExpression>("var"));
diff --git a/src/writer/hlsl/generator_impl_intrinsic_test.cc b/src/writer/hlsl/generator_impl_intrinsic_test.cc
index 9a00a3a..5287180 100644
--- a/src/writer/hlsl/generator_impl_intrinsic_test.cc
+++ b/src/writer/hlsl/generator_impl_intrinsic_test.cc
@@ -76,9 +76,21 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &vec2);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec2,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* b =
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "b",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList params;
   params.push_back(create<ast::IdentifierExpression>("a"));
@@ -115,8 +127,10 @@
 
   ast::CallExpression call(create<ast::IdentifierExpression>("dot"), params);
 
-  ast::Variable v1(Source{}, "param1", ast::StorageClass::kFunction, &vec);
-  ast::Variable v2(Source{}, "param2", ast::StorageClass::kFunction, &vec);
+  ast::Variable v1(Source{}, "param1", ast::StorageClass::kFunction, &vec,
+                   false, nullptr, ast::VariableDecorationList{});
+  ast::Variable v2(Source{}, "param2", ast::StorageClass::kFunction, &vec,
+                   false, nullptr, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v1);
   td.RegisterVariableForTesting(&v2);
diff --git a/src/writer/hlsl/generator_impl_loop_test.cc b/src/writer/hlsl/generator_impl_loop_test.cc
index d79af0a..383442e 100644
--- a/src/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/writer/hlsl/generator_impl_loop_test.cc
@@ -144,15 +144,26 @@
 
   ast::type::F32 f32;
 
-  auto* var = create<ast::Variable>(Source{}, "lhs",
-                                    ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.4)));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "lhs",                         // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.4)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
-  body->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "other", ast::StorageClass::kFunction, &f32)));
+  body->append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "other",                           // name
+                            ast::StorageClass::kFunction,      // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("lhs");
   auto* rhs = create<ast::IdentifierExpression>("rhs");
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index 5e1cc955..ccf706d 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -17,7 +17,6 @@
 #include "src/ast/array_accessor_expression.h"
 #include "src/ast/assignment_statement.h"
 #include "src/ast/binary_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/member_accessor_expression.h"
@@ -35,6 +34,7 @@
 #include "src/ast/type/struct_type.h"
 #include "src/ast/type/vector_type.h"
 #include "src/ast/type_constructor_expression.h"
+#include "src/ast/variable.h"
 #include "src/type_determiner.h"
 #include "src/writer/hlsl/test_helper.h"
 
@@ -57,8 +57,14 @@
 
   ast::type::Struct s("Str", strct);
 
-  auto* str_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "str", ast::StorageClass::kPrivate, &s));
+  auto* str_var =
+      create<ast::Variable>(Source{},                        // source
+                            "str",                           // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &s,                              // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* str = create<ast::IdentifierExpression>("str");
   auto* mem = create<ast::IdentifierExpression>("mem");
@@ -100,8 +106,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("data"),
                                      create<ast::IdentifierExpression>("b"));
@@ -143,8 +155,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("data"),
                                      create<ast::IdentifierExpression>("a"));
@@ -190,10 +208,22 @@
   ast::type::Struct s("Data", str);
 
   auto* b_var =
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kPrivate, &mat);
+      create<ast::Variable>(Source{},                        // source
+                            "b",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
-  auto* coord_var = create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   auto* lhs = create<ast::MemberAccessorExpression>(
       create<ast::IdentifierExpression>("data"),
@@ -249,8 +279,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   auto* lhs = create<ast::MemberAccessorExpression>(
       create<ast::IdentifierExpression>("data"),
@@ -304,8 +340,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("data"),
                                      create<ast::IdentifierExpression>("a"));
@@ -354,8 +396,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("data"),
                                      create<ast::IdentifierExpression>("a"));
@@ -396,8 +444,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("data"),
                                      create<ast::IdentifierExpression>("a"));
@@ -442,8 +496,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::ArrayAccessorExpression expr(
       create<ast::ArrayAccessorExpression>(
@@ -491,8 +551,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::ArrayAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -537,8 +603,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   ast::ArrayAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -593,8 +665,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -641,8 +719,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -693,8 +777,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -744,8 +834,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -790,8 +886,14 @@
 
   ast::type::Struct s("Data", str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &s));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &s,                                 // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -868,8 +970,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -939,8 +1047,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -1011,8 +1125,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -1082,8 +1202,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -1154,8 +1280,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
@@ -1237,8 +1369,14 @@
 
   ast::type::Struct pre_struct("Pre", pre_str);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &pre_struct));
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &pre_struct,                        // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{});     // decorations
 
   td.RegisterVariableForTesting(coord_var);
   gen.register_global(coord_var);
diff --git a/src/writer/hlsl/generator_impl_module_constant_test.cc b/src/writer/hlsl/generator_impl_module_constant_test.cc
index 4786c4d..c98882f 100644
--- a/src/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/writer/hlsl/generator_impl_module_constant_test.cc
@@ -16,7 +16,6 @@
 #include <vector>
 
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/module.h"
 #include "src/ast/scalar_constructor_expression.h"
@@ -45,10 +44,14 @@
   exprs.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 3.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "pos", ast::StorageClass::kNone, &ary);
-  var->set_is_const(true);
-  var->set_constructor(create<ast::TypeConstructorExpression>(&ary, exprs));
+  auto* var = create<ast::Variable>(
+      Source{},                                             // source
+      "pos",                                                // name
+      ast::StorageClass::kNone,                             // storage_class
+      &ary,                                                 // type
+      true,                                                 // is_const
+      create<ast::TypeConstructorExpression>(&ary, exprs),  // constructor
+      ast::VariableDecorationList{});                       // decorations
 
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
@@ -57,15 +60,18 @@
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(23, Source{}));
-
-  auto* var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "pos", ast::StorageClass::kNone, &f32));
-  var->set_decorations(decos);
-  var->set_is_const(true);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 3.0f)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "pos",                     // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      true,                      // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 3.0f)),  // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::ConstantIdDecoration>(23, Source{}),
+      });
 
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
@@ -79,13 +85,17 @@
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(23, Source{}));
-
-  auto* var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "pos", ast::StorageClass::kNone, &f32));
-  var->set_decorations(decos);
-  var->set_is_const(true);
+  auto* var =
+      create<ast::Variable>(Source{},                  // source
+                            "pos",                     // name
+                            ast::StorageClass::kNone,  // storage_class
+                            &f32,                      // type
+                            true,                      // is_const
+                            nullptr,                   // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::ConstantIdDecoration>(23, Source{}),
+                            });
 
   ASSERT_TRUE(gen.EmitProgramConstVariable(out, var)) << gen.error();
   EXPECT_EQ(result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
diff --git a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index e006551..35e2387 100644
--- a/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -35,7 +35,13 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   gen.increment_indent();
@@ -47,8 +53,13 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_is_const(true);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   gen.increment_indent();
@@ -62,7 +73,13 @@
   ast::type::Array ary(&f32, 5, ast::ArrayDecorationList{});
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &ary);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &ary,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   gen.increment_indent();
@@ -75,7 +92,13 @@
        Emit_VariableDeclStatement_Function) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   gen.increment_indent();
@@ -87,7 +110,13 @@
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   gen.increment_indent();
@@ -102,8 +131,13 @@
 
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(ident);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            ident,                           // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   ASSERT_TRUE(gen.EmitStatement(out, &stmt)) << gen.error();
@@ -120,8 +154,13 @@
   auto* zero_vec = create<ast::TypeConstructorExpression>(&vec, values);
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &vec);
-  var->set_constructor(zero_vec);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec,                            // type
+                            false,                           // is_const
+                            zero_vec,                        // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   ASSERT_TRUE(gen.EmitStatement(out, &stmt)) << gen.error();
@@ -138,8 +177,13 @@
   auto* zero_mat = create<ast::TypeConstructorExpression>(&mat, values);
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &mat);
-  var->set_constructor(zero_mat);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            zero_mat,                        // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
   ASSERT_TRUE(gen.EmitStatement(out, &stmt)) << gen.error();
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 9bb21f1..000c3d7 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -29,8 +29,8 @@
 #include "src/ast/call_expression.h"
 #include "src/ast/call_statement.h"
 #include "src/ast/case_statement.h"
+#include "src/ast/constant_id_decoration.h"
 #include "src/ast/continue_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/fallthrough_statement.h"
 #include "src/ast/float_literal.h"
@@ -63,6 +63,7 @@
 #include "src/ast/type/void_type.h"
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/writer/float_to_string.h"
 
@@ -1507,13 +1508,12 @@
 }
 
 bool GeneratorImpl::global_is_in_struct(ast::Variable* var) const {
-  auto* decorated = var->As<ast::DecoratedVariable>();
   bool in_or_out_struct_has_location =
-      decorated != nullptr && decorated->HasLocationDecoration() &&
+      var != nullptr && var->HasLocationDecoration() &&
       (var->storage_class() == ast::StorageClass::kInput ||
        var->storage_class() == ast::StorageClass::kOutput);
   bool in_struct_has_builtin =
-      decorated != nullptr && decorated->HasBuiltinDecoration() &&
+      var != nullptr && var->HasBuiltinDecoration() &&
       var->storage_class() == ast::StorageClass::kOutput;
   return in_or_out_struct_has_location || in_struct_has_builtin;
 }
@@ -2013,11 +2013,10 @@
   make_indent();
 
   // TODO(dsinclair): Handle variable decorations
-  if (var->Is<ast::DecoratedVariable>()) {
+  if (!var->decorations().empty()) {
     error_ = "Variable decorations are not handled yet";
     return false;
   }
-
   if (var->is_const()) {
     out_ << "const ";
   }
@@ -2051,10 +2050,11 @@
 bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
   make_indent();
 
-  auto* decorated = var->As<ast::DecoratedVariable>();
-  if (decorated != nullptr && !decorated->HasConstantIdDecoration()) {
-    error_ = "Decorated const values not valid";
-    return false;
+  for (auto* d : var->decorations()) {
+    if (!d->Is<ast::ConstantIdDecoration>()) {
+      error_ = "Decorated const values not valid";
+      return false;
+    }
   }
   if (!var->is_const()) {
     error_ = "Expected a const value";
@@ -2069,8 +2069,8 @@
     out_ << " " << var->name();
   }
 
-  if (decorated != nullptr && decorated->HasConstantIdDecoration()) {
-    out_ << " [[function_constant(" << decorated->constant_id() << ")]]";
+  if (var->HasConstantIdDecoration()) {
+    out_ << " [[function_constant(" << var->constant_id() << ")]]";
   } else if (var->constructor() != nullptr) {
     out_ << " = ";
     if (!EmitExpression(var->constructor())) {
diff --git a/src/writer/msl/generator_impl_function_entry_point_data_test.cc b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
index 8614c9f..ac6b4c8 100644
--- a/src/writer/msl/generator_impl_function_entry_point_data_test.cc
+++ b/src/writer/msl/generator_impl_function_entry_point_data_test.cc
@@ -16,7 +16,6 @@
 
 #include "gtest/gtest.h"
 #include "src/ast/assignment_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/identifier_expression.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/member_accessor_expression.h"
@@ -51,13 +50,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -105,13 +120,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -159,13 +190,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -212,13 +259,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -263,17 +326,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(0, Source{}));
-  foo_var->set_decorations(decos);
-
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kInput, &i32));
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                   // source
+                            "bar",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &i32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -313,17 +388,29 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kOutput, &f32));
+  auto* foo_var =
+      create<ast::Variable>(Source{},                    // source
+                            "foo",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(0, Source{}));
-  foo_var->set_decorations(decos);
-
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &i32));
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &i32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -369,15 +456,29 @@
   ast::type::Void void_type;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index 5e14775..03934cb 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -17,7 +17,6 @@
 #include "src/ast/binary_expression.h"
 #include "src/ast/binding_decoration.h"
 #include "src/ast/call_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
@@ -106,9 +105,21 @@
 
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   params.push_back(
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kNone, &i32));
+      create<ast::Variable>(Source{},                         // source
+                            "b",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &i32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   ast::type::Void void_type;
 
@@ -134,13 +145,29 @@
   ast::type::Void void_type;
   ast::type::F32 f32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -190,15 +217,29 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
@@ -246,24 +287,34 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kUniform, &vec4));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                     // source
+                            "coord",                      // name
+                            ast::StorageClass::kUniform,  // storage_class
+                            &vec4,                        // type
+                            false,                        // is_const
+                            nullptr,                      // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("x")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("x")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -312,24 +363,34 @@
 
   mod.AddConstructedType(&s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("b")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("b")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -382,13 +443,18 @@
 
   mod.AddConstructedType(&s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
@@ -396,11 +462,16 @@
 
   ast::VariableList params;
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::MemberAccessorExpression>(
-      create<ast::IdentifierExpression>("coord"),
-      create<ast::IdentifierExpression>("b")));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::MemberAccessorExpression>(
+          create<ast::IdentifierExpression>("coord"),
+          create<ast::IdentifierExpression>("b")),  // constructor
+      ast::VariableDecorationList{});               // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -438,17 +509,41 @@
   ast::type::Void void_type;
   ast::type::F32 f32;
 
-  auto* foo_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "foo", ast::StorageClass::kInput, &f32));
-  foo_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* foo_var =
+      create<ast::Variable>(Source{},                   // source
+                            "foo",                      // name
+                            ast::StorageClass::kInput,  // storage_class
+                            &f32,                       // type
+                            false,                      // is_const
+                            nullptr,                    // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  bar_var->set_decorations({create<ast::LocationDecoration>(1, Source{})});
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
-  auto* val_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "val", ast::StorageClass::kOutput, &f32));
-  val_var->set_decorations({create<ast::LocationDecoration>(0, Source{})});
+  auto* val_var =
+      create<ast::Variable>(Source{},                    // source
+                            "val",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(0, Source{}),
+                            });
 
   td.RegisterVariableForTesting(foo_var);
   td.RegisterVariableForTesting(bar_var);
@@ -459,8 +554,14 @@
   mod.AddGlobalVariable(val_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::AssignmentStatement>(
@@ -529,21 +630,31 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(
-      create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}));
-  depth_var->set_decorations(decos);
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(depth_var);
 
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -601,15 +712,29 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kInput, &vec4));
-  coord_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{})});
+  auto* coord_var = create<ast::Variable>(
+      Source{},                   // source
+      "coord",                    // name
+      ast::StorageClass::kInput,  // storage_class
+      &vec4,                      // type
+      false,                      // is_const
+      nullptr,                    // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragCoord, Source{}),
+      });
 
-  auto* depth_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "depth", ast::StorageClass::kOutput, &f32));
-  depth_var->set_decorations(
-      {create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{})});
+  auto* depth_var = create<ast::Variable>(
+      Source{},                    // source
+      "depth",                     // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kFragDepth, Source{}),
+      });
 
   td.RegisterVariableForTesting(coord_var);
   td.RegisterVariableForTesting(depth_var);
@@ -618,8 +743,14 @@
   mod.AddGlobalVariable(depth_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::AssignmentStatement>(
@@ -680,21 +811,32 @@
   ast::type::F32 f32;
   ast::type::Vector vec4(&f32, 4);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kUniform, &vec4));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                     // source
+                            "coord",                      // name
+                            ast::StorageClass::kUniform,  // storage_class
+                            &vec4,                        // type
+                            false,                        // is_const
+                            nullptr,                      // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
 
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -710,10 +852,15 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::CallExpression>(
-      create<ast::IdentifierExpression>("sub_func"), expr));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::CallExpression>(create<ast::IdentifierExpression>("sub_func"),
+                                  expr),  // constructor
+      ast::VariableDecorationList{});     // decorations
 
   body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -765,20 +912,31 @@
 
   mod.AddConstructedType(&s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -794,10 +952,15 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::CallExpression>(
-      create<ast::IdentifierExpression>("sub_func"), expr));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::CallExpression>(create<ast::IdentifierExpression>("sub_func"),
+                                  expr),  // constructor
+      ast::VariableDecorationList{});     // decorations
 
   body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -855,20 +1018,31 @@
 
   mod.AddConstructedType(&s);
 
-  auto* coord_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "coord", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  coord_var->set_decorations(decos);
+  auto* coord_var =
+      create<ast::Variable>(Source{},                           // source
+                            "coord",                            // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(coord_var);
   mod.AddGlobalVariable(coord_var);
 
   ast::VariableList params;
-  params.push_back(create<ast::Variable>(Source{}, "param",
-                                         ast::StorageClass::kFunction, &f32));
+  params.push_back(
+      create<ast::Variable>(Source{},                         // source
+                            "param",                          // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -884,10 +1058,15 @@
   expr.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::CallExpression>(
-      create<ast::IdentifierExpression>("sub_func"), expr));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "v",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::CallExpression>(create<ast::IdentifierExpression>("sub_func"),
+                                  expr),  // constructor
+      ast::VariableDecorationList{});     // decorations
 
   body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
@@ -929,11 +1108,17 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  auto* bar_var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "bar", ast::StorageClass::kOutput, &f32));
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(1, Source{}));
-  bar_var->set_decorations(decos);
+  auto* bar_var =
+      create<ast::Variable>(Source{},                    // source
+                            "bar",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(1, Source{}),
+                            });
 
   td.RegisterVariableForTesting(bar_var);
   mod.AddGlobalVariable(bar_var);
@@ -1015,7 +1200,13 @@
 
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &ary));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &ary,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   ast::type::Void void_type;
 
@@ -1072,13 +1263,18 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* data_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(0, Source{}));
-  data_var->set_decorations(decos);
+  auto* data_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(0, Source{}),
+                            });
 
   mod.AddConstructedType(&s);
 
@@ -1087,11 +1283,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
@@ -1109,11 +1310,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
diff --git a/src/writer/msl/generator_impl_import_test.cc b/src/writer/msl/generator_impl_import_test.cc
index b25f6ab..76b5e1c 100644
--- a/src/writer/msl/generator_impl_import_test.cc
+++ b/src/writer/msl/generator_impl_import_test.cc
@@ -267,8 +267,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "var",
-                                    ast::StorageClass::kFunction, &mat);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "var",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList params;
   params.push_back(create<ast::IdentifierExpression>("var"));
diff --git a/src/writer/msl/generator_impl_intrinsic_test.cc b/src/writer/msl/generator_impl_intrinsic_test.cc
index 164cee6..33b5a63 100644
--- a/src/writer/msl/generator_impl_intrinsic_test.cc
+++ b/src/writer/msl/generator_impl_intrinsic_test.cc
@@ -71,9 +71,21 @@
   ast::type::Vector vec3(&f32, 3);
 
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &vec2);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec2,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* b =
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kNone, &vec3);
+      create<ast::Variable>(Source{},                        // source
+                            "b",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList params;
   params.push_back(create<ast::IdentifierExpression>("a"));
@@ -110,8 +122,10 @@
 
   ast::CallExpression call(create<ast::IdentifierExpression>("dot"), params);
 
-  ast::Variable v1(Source{}, "param1", ast::StorageClass::kFunction, &vec);
-  ast::Variable v2(Source{}, "param2", ast::StorageClass::kFunction, &vec);
+  ast::Variable v1(Source{}, "param1", ast::StorageClass::kFunction, &vec,
+                   false, nullptr, ast::VariableDecorationList{});
+  ast::Variable v2(Source{}, "param2", ast::StorageClass::kFunction, &vec,
+                   false, nullptr, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v1);
   td.RegisterVariableForTesting(&v2);
diff --git a/src/writer/msl/generator_impl_loop_test.cc b/src/writer/msl/generator_impl_loop_test.cc
index bd05c99..fa18cb3 100644
--- a/src/writer/msl/generator_impl_loop_test.cc
+++ b/src/writer/msl/generator_impl_loop_test.cc
@@ -149,15 +149,26 @@
 
   ast::type::F32 f32;
 
-  auto* var = create<ast::Variable>(Source{}, "lhs",
-                                    ast::StorageClass::kFunction, &f32);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.4)));
+  auto* var = create<ast::Variable>(
+      Source{},                      // source
+      "lhs",                         // name
+      ast::StorageClass::kFunction,  // storage_class
+      &f32,                          // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.4)),  // constructor
+      ast::VariableDecorationList{});             // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::VariableDeclStatement>(var));
-  body->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "other", ast::StorageClass::kFunction, &f32)));
+  body->append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "other",                           // name
+                            ast::StorageClass::kFunction,      // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("lhs");
   auto* rhs = create<ast::IdentifierExpression>("rhs");
diff --git a/src/writer/msl/generator_impl_module_constant_test.cc b/src/writer/msl/generator_impl_module_constant_test.cc
index fc5739a..efe5ee0 100644
--- a/src/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/writer/msl/generator_impl_module_constant_test.cc
@@ -17,7 +17,6 @@
 
 #include "gtest/gtest.h"
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/module.h"
 #include "src/ast/scalar_constructor_expression.h"
@@ -47,10 +46,14 @@
   exprs.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 3.0f)));
 
-  auto* var =
-      create<ast::Variable>(Source{}, "pos", ast::StorageClass::kNone, &ary);
-  var->set_is_const(true);
-  var->set_constructor(create<ast::TypeConstructorExpression>(&ary, exprs));
+  auto* var = create<ast::Variable>(
+      Source{},                                             // source
+      "pos",                                                // name
+      ast::StorageClass::kNone,                             // storage_class
+      &ary,                                                 // type
+      true,                                                 // is_const
+      create<ast::TypeConstructorExpression>(&ary, exprs),  // constructor
+      ast::VariableDecorationList{});                       // decorations
 
   ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
   EXPECT_EQ(gen.result(), "constant float pos[3] = {1.0f, 2.0f, 3.0f};\n");
@@ -59,15 +62,18 @@
 TEST_F(MslGeneratorImplTest, Emit_SpecConstant) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(23, Source{}));
-
-  auto* var = create<ast::DecoratedVariable>(
-      create<ast::Variable>(Source{}, "pos", ast::StorageClass::kNone, &f32));
-  var->set_decorations(decos);
-  var->set_is_const(true);
-  var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 3.0f)));
+  auto* var = create<ast::Variable>(
+      Source{},                  // source
+      "pos",                     // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      true,                      // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 3.0f)),  // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::ConstantIdDecoration>(23, Source{}),
+      });
 
   ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
   EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
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 f8eac4a..8397d50 100644
--- a/src/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -43,7 +43,13 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -56,8 +62,13 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_is_const(true);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -72,7 +83,13 @@
   ast::type::Array ary(&f32, 5, ast::ArrayDecorationList{});
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &ary);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &ary,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -98,7 +115,13 @@
   ast::type::Struct s("S", str);
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &s);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &s,                              // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -114,7 +137,13 @@
   ast::type::Vector vec(&f32, 2);
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &vec);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &vec,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -128,7 +157,13 @@
   ast::type::F32 f32;
   ast::type::Matrix mat(&f32, 2, 3);
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &mat);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -141,7 +176,13 @@
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -156,8 +197,13 @@
 
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
-  var->set_constructor(ident);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            ident,                           // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -174,8 +220,13 @@
   auto* zero_vec = create<ast::TypeConstructorExpression>(&vec, values);
 
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &vec);
-  var->set_constructor(zero_vec);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &vec,                            // type
+                            false,                           // is_const
+                            zero_vec,                        // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index ae26598..244844e 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -34,7 +34,6 @@
 #include "src/ast/case_statement.h"
 #include "src/ast/constant_id_decoration.h"
 #include "src/ast/constructor_expression.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/fallthrough_statement.h"
 #include "src/ast/float_literal.h"
@@ -72,6 +71,7 @@
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/writer/append_vector.h"
 
@@ -739,8 +739,7 @@
     //    one
     // 2- If we don't have a constructor and we're an Output or Private variable
     //    then WGSL requires an initializer.
-    auto* decorated = var->As<ast::DecoratedVariable>();
-    if (decorated != nullptr && decorated->HasConstantIdDecoration()) {
+    if (var->HasConstantIdDecoration()) {
       if (type->Is<ast::type::F32>()) {
         ast::FloatLiteral l(type, 0.0f);
         init_id = GenerateLiteralIfNeeded(var, &l);
@@ -775,33 +774,31 @@
 
   push_type(spv::Op::OpVariable, std::move(ops));
 
-  if (auto* decorated = var->As<ast::DecoratedVariable>()) {
-    for (auto* deco : decorated->decorations()) {
-      if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
-        push_annot(spv::Op::OpDecorate,
-                   {Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
-                    Operand::Int(ConvertBuiltin(builtin->value()))});
-      } else if (auto* location = deco->As<ast::LocationDecoration>()) {
-        push_annot(spv::Op::OpDecorate,
-                   {Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
-                    Operand::Int(location->value())});
-      } else if (auto* binding = deco->As<ast::BindingDecoration>()) {
-        push_annot(spv::Op::OpDecorate,
-                   {Operand::Int(var_id), Operand::Int(SpvDecorationBinding),
-                    Operand::Int(binding->value())});
-      } else if (auto* set = deco->As<ast::SetDecoration>()) {
-        push_annot(
-            spv::Op::OpDecorate,
-            {Operand::Int(var_id), Operand::Int(SpvDecorationDescriptorSet),
-             Operand::Int(set->value())});
-      } else if (deco->Is<ast::ConstantIdDecoration>()) {
-        // Spec constants are handled elsewhere
-      } else {
-        error_ = "unknown decoration";
-        return false;
-      }
+  for (auto* deco : var->decorations()) {
+    if (auto* builtin = deco->As<ast::BuiltinDecoration>()) {
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
+                  Operand::Int(ConvertBuiltin(builtin->value()))});
+    } else if (auto* location = deco->As<ast::LocationDecoration>()) {
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
+                  Operand::Int(location->value())});
+    } else if (auto* binding = deco->As<ast::BindingDecoration>()) {
+      push_annot(spv::Op::OpDecorate,
+                 {Operand::Int(var_id), Operand::Int(SpvDecorationBinding),
+                  Operand::Int(binding->value())});
+    } else if (auto* set = deco->As<ast::SetDecoration>()) {
+      push_annot(spv::Op::OpDecorate, {Operand::Int(var_id),
+                                       Operand::Int(SpvDecorationDescriptorSet),
+                                       Operand::Int(set->value())});
+    } else if (deco->Is<ast::ConstantIdDecoration>()) {
+      // Spec constants are handled elsewhere
+    } else {
+      error_ = "unknown decoration";
+      return false;
     }
   }
+
   scope_stack_.set_global(var->name(), var_id);
   spirv_id_to_variable_[var_id] = var;
   return true;
@@ -1455,8 +1452,7 @@
 
   auto name = lit->name();
   bool is_spec_constant = false;
-  if (var && var->Is<ast::DecoratedVariable>() &&
-      var->As<ast::DecoratedVariable>()->HasConstantIdDecoration()) {
+  if (var && var->HasConstantIdDecoration()) {
     name = "__spec" + name;
     is_spec_constant = true;
   }
@@ -1470,10 +1466,9 @@
   auto result_id = result.to_i();
 
   if (is_spec_constant) {
-    push_annot(
-        spv::Op::OpDecorate,
-        {Operand::Int(result_id), Operand::Int(SpvDecorationSpecId),
-         Operand::Int(var->As<ast::DecoratedVariable>()->constant_id())});
+    push_annot(spv::Op::OpDecorate,
+               {Operand::Int(result_id), Operand::Int(SpvDecorationSpecId),
+                Operand::Int(var->constant_id())});
   }
 
   if (auto* l = lit->As<ast::BoolLiteral>()) {
diff --git a/src/writer/spirv/builder_accessor_expression_test.cc b/src/writer/spirv/builder_accessor_expression_test.cc
index 604ffa5..f46d48e 100644
--- a/src/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/writer/spirv/builder_accessor_expression_test.cc
@@ -53,7 +53,8 @@
   // vec3<f32> ary;
   // ary[1]  -> ptr<f32>
 
-  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3, false,
+                    nullptr, ast::VariableDecorationList{});
 
   auto* ary = create<ast::IdentifierExpression>("ary");
   auto* idx_expr = create<ast::ScalarConstructorExpression>(
@@ -94,8 +95,10 @@
   // idx : i32;
   // ary[idx]  -> ptr<f32>
 
-  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3);
-  ast::Variable idx(Source{}, "idx", ast::StorageClass::kFunction, &i32);
+  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3, false,
+                    nullptr, ast::VariableDecorationList{});
+  ast::Variable idx(Source{}, "idx", ast::StorageClass::kFunction, &i32, false,
+                    nullptr, ast::VariableDecorationList{});
 
   auto* ary = create<ast::IdentifierExpression>("ary");
   auto* idx_expr = create<ast::IdentifierExpression>("idx");
@@ -139,7 +142,8 @@
   // vec3<f32> ary;
   // ary[1 + 2]  -> ptr<f32>
 
-  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &vec3, false,
+                    nullptr, ast::VariableDecorationList{});
 
   auto* ary = create<ast::IdentifierExpression>("ary");
 
@@ -186,7 +190,8 @@
   // ary = array<vec3<f32>, 4>
   // ary[3][2];
 
-  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &ary4);
+  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &ary4, false,
+                    nullptr, ast::VariableDecorationList{});
 
   ast::ArrayAccessorExpression expr(
       create<ast::ArrayAccessorExpression>(
@@ -233,7 +238,8 @@
   // var a : array<vec3<f32>, 4>;
   // a[2].xy;
 
-  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &ary4);
+  ast::Variable var(Source{}, "ary", ast::StorageClass::kFunction, &ary4, false,
+                    nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::ArrayAccessorExpression>(
@@ -289,7 +295,8 @@
   auto* s = create<ast::Struct>(members);
   ast::type::Struct s_type("my_struct", s);
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("ident"),
                                      create<ast::IdentifierExpression>("b"));
@@ -343,7 +350,8 @@
 
   ast::type::Struct s_type("my_struct", create<ast::Struct>(outer_members));
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -403,7 +411,8 @@
 
   ast::type::Struct s_type("Outer", create<ast::Struct>(outer_members));
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -462,7 +471,8 @@
 
   ast::type::Struct s_type("my_struct", create<ast::Struct>(outer_members));
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                    false, nullptr, ast::VariableDecorationList{});
 
   auto* lhs = create<ast::MemberAccessorExpression>(
       create<ast::MemberAccessorExpression>(
@@ -528,8 +538,10 @@
 
   ast::type::Struct s_type("my_struct", create<ast::Struct>(outer_members));
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
-  ast::Variable store(Source{}, "store", ast::StorageClass::kFunction, &f32);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                    false, nullptr, ast::VariableDecorationList{});
+  ast::Variable store(Source{}, "store", ast::StorageClass::kFunction, &f32,
+                      false, nullptr, ast::VariableDecorationList{});
 
   auto* lhs = create<ast::IdentifierExpression>("store");
 
@@ -578,7 +590,8 @@
 
   // ident.y
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("ident"),
                                      create<ast::IdentifierExpression>("y"));
@@ -613,7 +626,8 @@
 
   // ident.yx
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(create<ast::IdentifierExpression>("ident"),
                                      create<ast::IdentifierExpression>("yx"));
@@ -647,7 +661,8 @@
 
   // ident.yxz.xz
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -685,7 +700,8 @@
 
   // ident.yxz.x
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -723,7 +739,8 @@
 
   // index.yxz[1]
 
-  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3);
+  ast::Variable var(Source{}, "ident", ast::StorageClass::kFunction, &vec3,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::ArrayAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -793,7 +810,7 @@
   ast::type::Array a_ary_type(&a_type, 2, ast::ArrayDecorationList{});
 
   ast::Variable var(Source{}, "index", ast::StorageClass::kFunction,
-                    &a_ary_type);
+                    &a_ary_type, false, nullptr, ast::VariableDecorationList{});
 
   ast::MemberAccessorExpression expr(
       create<ast::MemberAccessorExpression>(
@@ -885,9 +902,9 @@
                     create<ast::FloatLiteral>(&f32, -0.5)),
             }));
 
-  ast::Variable var(Source{}, "pos", ast::StorageClass::kPrivate, &arr);
-  var.set_is_const(true);
-  var.set_constructor(create<ast::TypeConstructorExpression>(&arr, ary_params));
+  ast::Variable var(Source{}, "pos", ast::StorageClass::kPrivate, &arr, true,
+                    create<ast::TypeConstructorExpression>(&arr, ary_params),
+                    ast::VariableDecorationList{});
 
   ast::ArrayAccessorExpression expr(create<ast::IdentifierExpression>("pos"),
                                     create<ast::ScalarConstructorExpression>(
@@ -941,10 +958,10 @@
   vec_params.push_back(create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 0.5)));
 
-  ast::Variable var(Source{}, "pos", ast::StorageClass::kPrivate, &vec);
-  var.set_is_const(true);
-  var.set_constructor(
-      create<ast::TypeConstructorExpression>(&vec, std::move(vec_params)));
+  ast::Variable var(
+      Source{}, "pos", ast::StorageClass::kPrivate, &vec, true,
+      create<ast::TypeConstructorExpression>(&vec, std::move(vec_params)),
+      ast::VariableDecorationList{});
 
   ast::ArrayAccessorExpression expr(create<ast::IdentifierExpression>("pos"),
                                     create<ast::ScalarConstructorExpression>(
diff --git a/src/writer/spirv/builder_assign_test.cc b/src/writer/spirv/builder_assign_test.cc
index 5a6d44c..cee9950 100644
--- a/src/writer/spirv/builder_assign_test.cc
+++ b/src/writer/spirv/builder_assign_test.cc
@@ -44,7 +44,8 @@
 TEST_F(BuilderTest, Assign_Var) {
   ast::type::F32 f32;
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::IdentifierExpression>("var");
   auto* val = create<ast::ScalarConstructorExpression>(
@@ -78,7 +79,8 @@
   ast::type::F32 f32;
   ast::type::Vector vec(&f32, 3);
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec, false,
+                  nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::IdentifierExpression>("var");
   ast::ExpressionList vals;
@@ -128,7 +130,8 @@
                      create<ast::FloatLiteral>(&f32, 3.0f)),
              });
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3, false,
+                  nullptr, ast::VariableDecorationList{});
 
   ast::AssignmentStatement assign(create<ast::IdentifierExpression>("var"),
                                   init);
@@ -176,7 +179,8 @@
 
   auto* init = create<ast::TypeConstructorExpression>(&vec3, vals);
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3, false,
+                  nullptr, ast::VariableDecorationList{});
 
   ast::AssignmentStatement assign(create<ast::IdentifierExpression>("var"),
                                   init);
@@ -223,7 +227,8 @@
   auto* s = create<ast::Struct>(members);
   ast::type::Struct s_type("my_struct", s);
 
-  ast::Variable v(Source{}, "ident", ast::StorageClass::kFunction, &s_type);
+  ast::Variable v(Source{}, "ident", ast::StorageClass::kFunction, &s_type,
+                  false, nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::MemberAccessorExpression>(
       create<ast::IdentifierExpression>("ident"),
@@ -265,7 +270,8 @@
   ast::type::F32 f32;
   ast::type::Vector vec3(&f32, 3);
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3, false,
+                  nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::IdentifierExpression>("var");
 
@@ -312,7 +318,8 @@
 
   // var.y = 1
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3, false,
+                  nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::MemberAccessorExpression>(
       create<ast::IdentifierExpression>("var"),
@@ -357,7 +364,8 @@
 
   // var[1] = 1
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &vec3, false,
+                  nullptr, ast::VariableDecorationList{});
 
   auto* ident = create<ast::ArrayAccessorExpression>(
       create<ast::IdentifierExpression>("var"),
diff --git a/src/writer/spirv/builder_binary_expression_test.cc b/src/writer/spirv/builder_binary_expression_test.cc
index 8920a66..60d9828 100644
--- a/src/writer/spirv/builder_binary_expression_test.cc
+++ b/src/writer/spirv/builder_binary_expression_test.cc
@@ -121,7 +121,8 @@
 
   ast::type::I32 i32;
 
-  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &i32);
+  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &i32,
+                    false, nullptr, ast::VariableDecorationList{});
 
   auto* lhs = create<ast::IdentifierExpression>("param");
   auto* rhs = create<ast::IdentifierExpression>("param");
@@ -633,8 +634,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
   auto* rhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.f));
@@ -666,8 +673,14 @@
   ast::type::F32 f32;
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::ScalarConstructorExpression>(
       create<ast::FloatLiteral>(&f32, 1.f));
   auto* rhs = create<ast::IdentifierExpression>("mat");
@@ -700,8 +713,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
 
   ast::ExpressionList vals;
@@ -742,8 +761,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::ExpressionList vals;
   vals.push_back(create<ast::ScalarConstructorExpression>(
@@ -785,8 +810,14 @@
   ast::type::Vector vec3(&f32, 3);
   ast::type::Matrix mat3(&f32, 3, 3);
 
-  auto* var = create<ast::Variable>(Source{}, "mat",
-                                    ast::StorageClass::kFunction, &mat3);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "mat",                           // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &mat3,                           // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* lhs = create<ast::IdentifierExpression>("mat");
   auto* rhs = create<ast::IdentifierExpression>("mat");
 
@@ -861,14 +892,24 @@
 TEST_F(BuilderTest, Binary_LogicalAnd_WithLoads) {
   ast::type::Bool bool_type;
 
-  auto* a_var = create<ast::Variable>(Source{}, "a",
-                                      ast::StorageClass::kFunction, &bool_type);
-  a_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::BoolLiteral>(&bool_type, true)));
-  auto* b_var = create<ast::Variable>(Source{}, "b",
-                                      ast::StorageClass::kFunction, &bool_type);
-  b_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::BoolLiteral>(&bool_type, false)));
+  auto* a_var = create<ast::Variable>(
+      Source{},                      // source
+      "a",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &bool_type,                    // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::BoolLiteral>(&bool_type, true)),  // constructor
+      ast::VariableDecorationList{});                   // decorations
+  auto* b_var = create<ast::Variable>(
+      Source{},                      // source
+      "b",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &bool_type,                    // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::BoolLiteral>(&bool_type, false)),  // constructor
+      ast::VariableDecorationList{});                    // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::IdentifierExpression>("b");
@@ -1047,14 +1088,24 @@
 TEST_F(BuilderTest, Binary_LogicalOr_WithLoads) {
   ast::type::Bool bool_type;
 
-  auto* a_var = create<ast::Variable>(Source{}, "a",
-                                      ast::StorageClass::kFunction, &bool_type);
-  a_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::BoolLiteral>(&bool_type, true)));
-  auto* b_var = create<ast::Variable>(Source{}, "b",
-                                      ast::StorageClass::kFunction, &bool_type);
-  b_var->set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::BoolLiteral>(&bool_type, false)));
+  auto* a_var = create<ast::Variable>(
+      Source{},                      // source
+      "a",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &bool_type,                    // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::BoolLiteral>(&bool_type, true)),  // constructor
+      ast::VariableDecorationList{});                   // decorations
+  auto* b_var = create<ast::Variable>(
+      Source{},                      // source
+      "b",                           // name
+      ast::StorageClass::kFunction,  // storage_class
+      &bool_type,                    // type
+      false,                         // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::BoolLiteral>(&bool_type, false)),  // constructor
+      ast::VariableDecorationList{});                    // decorations
 
   auto* lhs = create<ast::IdentifierExpression>("a");
   auto* rhs = create<ast::IdentifierExpression>("b");
diff --git a/src/writer/spirv/builder_block_test.cc b/src/writer/spirv/builder_block_test.cc
index 8be8d5e..9d82125 100644
--- a/src/writer/spirv/builder_block_test.cc
+++ b/src/writer/spirv/builder_block_test.cc
@@ -41,16 +41,28 @@
   // serves to prove the block code is pushing new scopes as needed.
   ast::BlockStatement outer;
 
-  outer.append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "var", ast::StorageClass::kFunction, &f32)));
+  outer.append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "var",                             // name
+                            ast::StorageClass::kFunction,      // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
   outer.append(create<ast::AssignmentStatement>(
       create<ast::IdentifierExpression>("var"),
       create<ast::ScalarConstructorExpression>(
           create<ast::FloatLiteral>(&f32, 1.0f))));
 
   auto* inner = create<ast::BlockStatement>();
-  inner->append(create<ast::VariableDeclStatement>(create<ast::Variable>(
-      Source{}, "var", ast::StorageClass::kFunction, &f32)));
+  inner->append(create<ast::VariableDeclStatement>(
+      create<ast::Variable>(Source{},                          // source
+                            "var",                             // name
+                            ast::StorageClass::kFunction,      // storage_class
+                            &f32,                              // type
+                            false,                             // is_const
+                            nullptr,                           // constructor
+                            ast::VariableDecorationList{})));  // decorations
   inner->append(create<ast::AssignmentStatement>(
       create<ast::IdentifierExpression>("var"),
       create<ast::ScalarConstructorExpression>(
diff --git a/src/writer/spirv/builder_call_test.cc b/src/writer/spirv/builder_call_test.cc
index fb83808..1f2d50b 100644
--- a/src/writer/spirv/builder_call_test.cc
+++ b/src/writer/spirv/builder_call_test.cc
@@ -44,9 +44,21 @@
 
   ast::VariableList func_params;
   func_params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   func_params.push_back(
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kFunction, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "b",                              // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -109,9 +121,21 @@
 
   ast::VariableList func_params;
   func_params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   func_params.push_back(
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kFunction, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "b",                              // name
+                            ast::StorageClass::kFunction,     // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
diff --git a/src/writer/spirv/builder_function_decoration_test.cc b/src/writer/spirv/builder_function_decoration_test.cc
index b796d34..6f835e1 100644
--- a/src/writer/spirv/builder_function_decoration_test.cc
+++ b/src/writer/spirv/builder_function_decoration_test.cc
@@ -103,11 +103,29 @@
       });
 
   auto* v_in =
-      create<ast::Variable>(Source{}, "my_in", ast::StorageClass::kInput, &f32);
-  auto* v_out = create<ast::Variable>(Source{}, "my_out",
-                                      ast::StorageClass::kOutput, &f32);
-  auto* v_wg = create<ast::Variable>(Source{}, "my_wg",
-                                     ast::StorageClass::kWorkgroup, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_in",                         // name
+                            ast::StorageClass::kInput,       // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* v_out =
+      create<ast::Variable>(Source{},                        // source
+                            "my_out",                        // name
+                            ast::StorageClass::kOutput,      // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* v_wg =
+      create<ast::Variable>(Source{},                        // source
+                            "my_wg",                         // name
+                            ast::StorageClass::kWorkgroup,   // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   EXPECT_TRUE(b.GenerateGlobalVariable(v_in)) << b.error();
   EXPECT_TRUE(b.GenerateGlobalVariable(v_out)) << b.error();
@@ -162,11 +180,29 @@
       });
 
   auto* v_in =
-      create<ast::Variable>(Source{}, "my_in", ast::StorageClass::kInput, &f32);
-  auto* v_out = create<ast::Variable>(Source{}, "my_out",
-                                      ast::StorageClass::kOutput, &f32);
-  auto* v_wg = create<ast::Variable>(Source{}, "my_wg",
-                                     ast::StorageClass::kWorkgroup, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "my_in",                         // name
+                            ast::StorageClass::kInput,       // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* v_out =
+      create<ast::Variable>(Source{},                        // source
+                            "my_out",                        // name
+                            ast::StorageClass::kOutput,      // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
+  auto* v_wg =
+      create<ast::Variable>(Source{},                        // source
+                            "my_wg",                         // name
+                            ast::StorageClass::kWorkgroup,   // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   td.RegisterVariableForTesting(v_in);
   td.RegisterVariableForTesting(v_out);
diff --git a/src/writer/spirv/builder_function_test.cc b/src/writer/spirv/builder_function_test.cc
index 659f3ea..51da306 100644
--- a/src/writer/spirv/builder_function_test.cc
+++ b/src/writer/spirv/builder_function_test.cc
@@ -17,7 +17,6 @@
 #include "gtest/gtest.h"
 #include "spirv/unified1/spirv.h"
 #include "spirv/unified1/spirv.hpp11"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/function.h"
 #include "src/ast/identifier_expression.h"
@@ -88,7 +87,13 @@
   ast::type::F32 f32;
 
   auto* var_a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   td.RegisterVariableForTesting(var_a);
 
   auto* body = create<ast::BlockStatement>();
@@ -142,15 +147,23 @@
   ast::type::F32 f32;
   ast::type::I32 i32;
 
-  ast::VariableList params;
-  auto* var_a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &f32);
-  var_a->set_is_const(true);
-  params.push_back(var_a);
-  auto* var_b =
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kFunction, &i32);
-  var_b->set_is_const(true);
-  params.push_back(var_b);
+  ast::VariableList params = {
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{}),  // decorations
+
+      create<ast::Variable>(Source{},                        // source
+                            "b",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &i32,                            // type
+                            true,                            // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{}),  // decorations
+  };
 
   auto* body = create<ast::BlockStatement>();
   body->append(create<ast::ReturnStatement>(
@@ -259,13 +272,18 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* data_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(0, Source{}));
-  data_var->set_decorations(decos);
+  auto* data_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(0, Source{}),
+                            });
 
   mod->AddConstructedType(&s);
 
@@ -274,11 +292,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
@@ -296,11 +319,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
diff --git a/src/writer/spirv/builder_function_variable_test.cc b/src/writer/spirv/builder_function_variable_test.cc
index 2ff1a23..31b030a 100644
--- a/src/writer/spirv/builder_function_variable_test.cc
+++ b/src/writer/spirv/builder_function_variable_test.cc
@@ -19,7 +19,6 @@
 #include "src/ast/binding_decoration.h"
 #include "src/ast/builtin.h"
 #include "src/ast/builtin_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/scalar_constructor_expression.h"
@@ -47,7 +46,8 @@
 
 TEST_F(BuilderTest, FunctionVar_NoStorageClass) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   b.push_function(Function{});
   EXPECT_TRUE(b.GenerateFunctionVariable(&v)) << b.error();
@@ -80,8 +80,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, false,
+                  init, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
 
@@ -126,8 +126,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kFunction, &vec);
-  v.set_constructor(init);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kFunction, &vec, false,
+                  init, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
   b.push_function(Function{});
@@ -164,12 +164,13 @@
 
   ASSERT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  v.set_constructor(init);
+  ast::Variable v(Source{}, "v", ast::StorageClass::kFunction, &f32, false,
+                  init, ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
-  ast::Variable v2(Source{}, "v2", ast::StorageClass::kFunction, &f32);
-  v2.set_constructor(create<ast::IdentifierExpression>("v"));
+  ast::Variable v2(Source{}, "v2", ast::StorageClass::kFunction, &f32, false,
+                   create<ast::IdentifierExpression>("v"),
+                   ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v2);
 
   ASSERT_TRUE(td.DetermineResultType(v2.constructor())) << td.error();
@@ -209,13 +210,13 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "v", ast::StorageClass::kFunction, &f32);
-  v.set_constructor(init);
+  ast::Variable v(Source{}, "v", ast::StorageClass::kFunction, &f32, false,
+                  init, ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
-  ast::Variable v2(Source{}, "v2", ast::StorageClass::kFunction, &f32);
-  v2.set_is_const(true);
-  v2.set_constructor(create<ast::IdentifierExpression>("v"));
+  ast::Variable v2(Source{}, "v2", ast::StorageClass::kFunction, &f32, true,
+                   create<ast::IdentifierExpression>("v"),
+                   ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v2);
 
   ASSERT_TRUE(td.DetermineResultType(v2.constructor())) << td.error();
@@ -257,9 +258,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
 
diff --git a/src/writer/spirv/builder_global_variable_test.cc b/src/writer/spirv/builder_global_variable_test.cc
index 71408bb..878c15a 100644
--- a/src/writer/spirv/builder_global_variable_test.cc
+++ b/src/writer/spirv/builder_global_variable_test.cc
@@ -20,7 +20,6 @@
 #include "src/ast/builtin.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/module.h"
@@ -52,7 +51,8 @@
 
 TEST_F(BuilderTest, GlobalVar_NoStorageClass) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
@@ -66,7 +66,8 @@
 
 TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
@@ -80,7 +81,8 @@
 
 TEST_F(BuilderTest, GlobalVar_WithStorageClass_Input) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kInput, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kInput, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
@@ -107,8 +109,9 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, false,
+                  init, ast::VariableDecorationList{});
+
   td.RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
@@ -142,9 +145,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
@@ -175,9 +177,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
@@ -214,9 +215,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
@@ -241,14 +241,18 @@
 TEST_F(BuilderTest, GlobalVar_WithLocation) {
   ast::type::F32 f32;
   auto* v =
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(5, Source{}));
+      create<ast::Variable>(Source{},                    // source
+                            "var",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::LocationDecoration>(5, Source{}),
+                            });
 
-  ast::DecoratedVariable dv(v);
-  dv.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&dv)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Location 5
@@ -263,15 +267,19 @@
 TEST_F(BuilderTest, GlobalVar_WithBindingAndSet) {
   ast::type::F32 f32;
   auto* v =
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(2, Source{}));
-  decos.push_back(create<ast::SetDecoration>(3, Source{}));
+      create<ast::Variable>(Source{},                    // source
+                            "var",                       // name
+                            ast::StorageClass::kOutput,  // storage_class
+                            &f32,                        // type
+                            false,                       // is_const
+                            nullptr,                     // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(2, Source{}),
+                                create<ast::SetDecoration>(3, Source{}),
+                            });
 
-  ast::DecoratedVariable dv(v);
-  dv.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&dv)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Binding 2
@@ -286,16 +294,19 @@
 
 TEST_F(BuilderTest, GlobalVar_WithBuiltin) {
   ast::type::F32 f32;
-  auto* v =
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  ast::VariableDecorationList decos;
-  decos.push_back(
-      create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}));
+  auto* v = create<ast::Variable>(
+      Source{},                    // source
+      "var",                       // name
+      ast::StorageClass::kOutput,  // storage_class
+      &f32,                        // type
+      false,                       // is_const
+      nullptr,                     // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}),
+      });
 
-  ast::DecoratedVariable dv(v);
-  dv.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&dv)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 BuiltIn Position
@@ -310,16 +321,20 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Bool) {
   ast::type::Bool bool_type;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(1200, Source{}));
+  auto* v = create<ast::Variable>(
+      Source{},                  // source
+      "var",                     // name
+      ast::StorageClass::kNone,  // storage_class
+      &bool_type,                // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::BoolLiteral>(&bool_type, true)),  // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::ConstantIdDecoration>(1200, Source{}),
+      });
 
-  ast::DecoratedVariable v(create<ast::Variable>(
-      Source{}, "var", ast::StorageClass::kNone, &bool_type));
-  v.set_decorations(decos);
-  v.set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::BoolLiteral>(&bool_type, true)));
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
@@ -334,14 +349,19 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Bool_NoConstructor) {
   ast::type::Bool bool_type;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(1200, Source{}));
+  auto* v = create<ast::Variable>(
+      Source{},                  // source
+      "var",                     // name
+      ast::StorageClass::kNone,  // storage_class
+      &bool_type,                // type
+      false,                     // is_const
+      nullptr,                   // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::ConstantIdDecoration>(1200, Source{}),
+      });
 
-  ast::DecoratedVariable v(create<ast::Variable>(
-      Source{}, "var", ast::StorageClass::kNone, &bool_type));
-  v.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 1200
@@ -356,16 +376,20 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(0, Source{}));
+  auto* v = create<ast::Variable>(
+      Source{},                  // source
+      "var",                     // name
+      ast::StorageClass::kNone,  // storage_class
+      &f32,                      // type
+      false,                     // is_const
+      create<ast::ScalarConstructorExpression>(
+          create<ast::FloatLiteral>(&f32, 2.0)),  // constructor
+      ast::VariableDecorationList{
+          // decorations
+          create<ast::ConstantIdDecoration>(0, Source{}),
+      });
 
-  ast::DecoratedVariable v(
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &f32));
-  v.set_decorations(decos);
-  v.set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::FloatLiteral>(&f32, 2.0)));
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
@@ -380,14 +404,19 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_F32_NoConstructor) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(0, Source{}));
+  auto* v =
+      create<ast::Variable>(Source{},                  // source
+                            "var",                     // name
+                            ast::StorageClass::kNone,  // storage_class
+                            &f32,                      // type
+                            false,                     // is_const
+                            nullptr,                   // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::ConstantIdDecoration>(0, Source{}),
+                            });
 
-  ast::DecoratedVariable v(
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &f32));
-  v.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
@@ -402,14 +431,19 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_I32_NoConstructor) {
   ast::type::I32 i32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(0, Source{}));
+  auto* v =
+      create<ast::Variable>(Source{},                  // source
+                            "var",                     // name
+                            ast::StorageClass::kNone,  // storage_class
+                            &i32,                      // type
+                            false,                     // is_const
+                            nullptr,                   // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::ConstantIdDecoration>(0, Source{}),
+                            });
 
-  ast::DecoratedVariable v(
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &i32));
-  v.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
@@ -424,14 +458,19 @@
 TEST_F(BuilderTest, GlobalVar_ConstantId_Scalar_U32_NoConstructor) {
   ast::type::U32 u32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::ConstantIdDecoration>(0, Source{}));
+  auto* v =
+      create<ast::Variable>(Source{},                  // source
+                            "var",                     // name
+                            ast::StorageClass::kNone,  // storage_class
+                            &u32,                      // type
+                            false,                     // is_const
+                            nullptr,                   // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::ConstantIdDecoration>(0, Source{}),
+                            });
 
-  ast::DecoratedVariable v(
-      create<ast::Variable>(Source{}, "var", ast::StorageClass::kNone, &u32));
-  v.set_decorations(decos);
-
-  EXPECT_TRUE(b.GenerateGlobalVariable(&v)) << b.error();
+  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
   EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
   EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %4 SpecId 0
@@ -493,7 +532,8 @@
   ast::type::Struct A("A", create<ast::Struct>(members));
   ast::type::AccessControl ac{ast::AccessControl::kReadOnly, &A};
 
-  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &ac);
+  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &ac,
+                    false, nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var)) << b.error();
 
@@ -529,7 +569,8 @@
   ast::type::Alias B("B", &A);
   ast::type::AccessControl ac{ast::AccessControl::kReadOnly, &B};
 
-  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &ac);
+  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &ac,
+                    false, nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var)) << b.error();
 
@@ -563,7 +604,8 @@
   ast::type::AccessControl ac{ast::AccessControl::kReadOnly, &A};
   ast::type::Alias B("B", &ac);
 
-  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &B);
+  ast::Variable var(Source{}, "b", ast::StorageClass::kStorageBuffer, &B, false,
+                    nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var)) << b.error();
 
@@ -597,8 +639,10 @@
   ast::type::AccessControl read{ast::AccessControl::kReadOnly, &A};
   ast::type::AccessControl rw{ast::AccessControl::kReadWrite, &A};
 
-  ast::Variable var_b(Source{}, "b", ast::StorageClass::kStorageBuffer, &read);
-  ast::Variable var_c(Source{}, "c", ast::StorageClass::kStorageBuffer, &rw);
+  ast::Variable var_b(Source{}, "b", ast::StorageClass::kStorageBuffer, &read,
+                      false, nullptr, ast::VariableDecorationList{});
+  ast::Variable var_c(Source{}, "c", ast::StorageClass::kStorageBuffer, &rw,
+                      false, nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var_b)) << b.error();
   EXPECT_TRUE(b.GenerateGlobalVariable(&var_c)) << b.error();
@@ -629,8 +673,8 @@
                                  ast::type::ImageFormat::kR32Uint);
   ASSERT_TRUE(td.DetermineStorageTextureSubtype(&type)) << td.error();
 
-  ast::Variable var_a(Source{}, "a", ast::StorageClass::kUniformConstant,
-                      &type);
+  ast::Variable var_a(Source{}, "a", ast::StorageClass::kUniformConstant, &type,
+                      false, nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var_a)) << b.error();
 
@@ -650,8 +694,8 @@
                                  ast::type::ImageFormat::kR32Uint);
   ASSERT_TRUE(td.DetermineStorageTextureSubtype(&type)) << td.error();
 
-  ast::Variable var_a(Source{}, "a", ast::StorageClass::kUniformConstant,
-                      &type);
+  ast::Variable var_a(Source{}, "a", ast::StorageClass::kUniformConstant, &type,
+                      false, nullptr, ast::VariableDecorationList{});
 
   EXPECT_TRUE(b.GenerateGlobalVariable(&var_a)) << b.error();
 
diff --git a/src/writer/spirv/builder_ident_expression_test.cc b/src/writer/spirv/builder_ident_expression_test.cc
index 2a48e53..18f25f3 100644
--- a/src/writer/spirv/builder_ident_expression_test.cc
+++ b/src/writer/spirv/builder_ident_expression_test.cc
@@ -53,9 +53,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
 
@@ -77,7 +76,8 @@
 
 TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
 
@@ -112,9 +112,8 @@
 
   EXPECT_TRUE(td.DetermineResultType(init)) << td.error();
 
-  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32);
-  v.set_constructor(init);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kOutput, &f32, true, init,
+                  ast::VariableDecorationList{});
   td.RegisterVariableForTesting(&v);
 
   EXPECT_TRUE(b.GenerateFunctionVariable(&v)) << b.error();
@@ -134,7 +133,8 @@
 
 TEST_F(BuilderTest, IdentifierExpression_FunctionVar) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32);
+  ast::Variable v(Source{}, "var", ast::StorageClass::kNone, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&v);
 
@@ -160,7 +160,8 @@
 TEST_F(BuilderTest, IdentifierExpression_Load) {
   ast::type::I32 i32;
 
-  ast::Variable var(Source{}, "var", ast::StorageClass::kPrivate, &i32);
+  ast::Variable var(Source{}, "var", ast::StorageClass::kPrivate, &i32, false,
+                    nullptr, ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&var);
 
@@ -190,10 +191,10 @@
 TEST_F(BuilderTest, IdentifierExpression_NoLoadConst) {
   ast::type::I32 i32;
 
-  ast::Variable var(Source{}, "var", ast::StorageClass::kNone, &i32);
-  var.set_constructor(create<ast::ScalarConstructorExpression>(
-      create<ast::SintLiteral>(&i32, 2)));
-  var.set_is_const(true);
+  ast::Variable var(Source{}, "var", ast::StorageClass::kNone, &i32, true,
+                    create<ast::ScalarConstructorExpression>(
+                        create<ast::SintLiteral>(&i32, 2)),
+                    ast::VariableDecorationList{});
 
   td.RegisterVariableForTesting(&var);
 
diff --git a/src/writer/spirv/builder_if_test.cc b/src/writer/spirv/builder_if_test.cc
index 565860f..c484be6 100644
--- a/src/writer/spirv/builder_if_test.cc
+++ b/src/writer/spirv/builder_if_test.cc
@@ -76,7 +76,13 @@
   //   v = 2;
   // }
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
@@ -124,7 +130,13 @@
   //   v = 3;
   // }
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
@@ -184,7 +196,13 @@
   //   v = 3;
   // }
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
@@ -256,7 +274,13 @@
   //   v = 5;
   // }
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
@@ -609,8 +633,14 @@
   // }
 
   ast::type::Bool bool_type;
-  auto* var = create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction,
-                                    &bool_type);
+  auto* var =
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &bool_type,                      // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   td.RegisterVariableForTesting(var);
 
   ast::IfStatement expr(Source{}, create<ast::IdentifierExpression>("a"),
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index f8f6984..9839711 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -1399,9 +1399,8 @@
 
   auto* var = Var("b", ast::StorageClass::kPrivate, &s_type);
 
-  auto* ptr_var = Var("ptr_var", ast::StorageClass::kPrivate, &ptr);
-  ptr_var->set_constructor(
-      create<ast::MemberAccessorExpression>(Expr("b"), Expr("a")));
+  Var("ptr_var", ast::StorageClass::kPrivate, &ptr,
+      create<ast::MemberAccessorExpression>(Expr("b"), Expr("a")), {});
 
   auto expr = Call("arrayLength", "ptr_var");
   ASSERT_TRUE(td.DetermineResultType(&expr)) << td.error();
diff --git a/src/writer/spirv/builder_loop_test.cc b/src/writer/spirv/builder_loop_test.cc
index dbaa6bc..6a5776c 100644
--- a/src/writer/spirv/builder_loop_test.cc
+++ b/src/writer/spirv/builder_loop_test.cc
@@ -66,7 +66,13 @@
   //   v = 2;
   // }
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
@@ -113,7 +119,13 @@
   // }
 
   auto* var =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* body = create<ast::BlockStatement>();
   body->append(
diff --git a/src/writer/spirv/builder_return_test.cc b/src/writer/spirv/builder_return_test.cc
index 91f1656..973efd6 100644
--- a/src/writer/spirv/builder_return_test.cc
+++ b/src/writer/spirv/builder_return_test.cc
@@ -81,7 +81,8 @@
 TEST_F(BuilderTest, Return_WithValue_GeneratesLoad) {
   ast::type::F32 f32;
 
-  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &f32);
+  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &f32,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::ReturnStatement ret(Source{},
                            create<ast::IdentifierExpression>("param"));
diff --git a/src/writer/spirv/builder_switch_test.cc b/src/writer/spirv/builder_switch_test.cc
index 5497511..8ae74b0 100644
--- a/src/writer/spirv/builder_switch_test.cc
+++ b/src/writer/spirv/builder_switch_test.cc
@@ -77,9 +77,21 @@
   // }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* case_1_body = create<ast::BlockStatement>();
   case_1_body->append(
@@ -158,9 +170,21 @@
   //  }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* default_body = create<ast::BlockStatement>();
   default_body->append(
@@ -224,9 +248,21 @@
   //  }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* case_1_body = create<ast::BlockStatement>();
   case_1_body->append(
@@ -320,9 +356,21 @@
   //  }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* case_1_body = create<ast::BlockStatement>();
   case_1_body->append(
@@ -412,9 +460,21 @@
   //  }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* case_1_body = create<ast::BlockStatement>();
   case_1_body->append(
@@ -460,9 +520,21 @@
   //  }
 
   auto* v =
-      create<ast::Variable>(Source{}, "v", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "v",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
   auto* a =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &i32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &i32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   auto* if_body = create<ast::BlockStatement>();
   if_body->append(create<ast::BreakStatement>());
diff --git a/src/writer/spirv/builder_unary_op_expression_test.cc b/src/writer/spirv/builder_unary_op_expression_test.cc
index ef8da21..ef173a5 100644
--- a/src/writer/spirv/builder_unary_op_expression_test.cc
+++ b/src/writer/spirv/builder_unary_op_expression_test.cc
@@ -98,7 +98,8 @@
   ast::type::F32 f32;
   ast::type::Vector vec(&f32, 3);
 
-  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &vec);
+  ast::Variable var(Source{}, "param", ast::StorageClass::kFunction, &vec,
+                    false, nullptr, ast::VariableDecorationList{});
 
   ast::UnaryOpExpression expr(ast::UnaryOp::kNegation,
                               create<ast::IdentifierExpression>("param"));
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 1257e7b..5abd8db 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -32,7 +32,6 @@
 #include "src/ast/constant_id_decoration.h"
 #include "src/ast/constructor_expression.h"
 #include "src/ast/continue_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/else_statement.h"
 #include "src/ast/float_literal.h"
 #include "src/ast/identifier_expression.h"
@@ -70,6 +69,7 @@
 #include "src/ast/type_constructor_expression.h"
 #include "src/ast/uint_literal.h"
 #include "src/ast/unary_op_expression.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decl_statement.h"
 #include "src/ast/workgroup_decoration.h"
 #include "src/writer/float_to_string.h"
@@ -582,10 +582,8 @@
 bool GeneratorImpl::EmitVariable(ast::Variable* var) {
   make_indent();
 
-  if (auto* decorated = var->As<ast::DecoratedVariable>()) {
-    if (!EmitVariableDecorations(decorated)) {
-      return false;
-    }
+  if (!var->decorations().empty() && !EmitVariableDecorations(var)) {
+    return false;
   }
 
   if (var->is_const()) {
@@ -614,7 +612,7 @@
   return true;
 }
 
-bool GeneratorImpl::EmitVariableDecorations(ast::DecoratedVariable* var) {
+bool GeneratorImpl::EmitVariableDecorations(ast::Variable* var) {
   out_ << "[[";
   bool first = true;
   for (auto* deco : var->decorations()) {
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index ba0544f..c4544e3 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -27,7 +27,6 @@
 #include "src/ast/case_statement.h"
 #include "src/ast/constructor_expression.h"
 #include "src/ast/continue_statement.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/fallthrough_statement.h"
 #include "src/ast/identifier_expression.h"
@@ -206,7 +205,7 @@
   /// Handles generating variable decorations
   /// @param var the decorated variable
   /// @returns true if the variable decoration was emitted
-  bool EmitVariableDecorations(ast::DecoratedVariable* var);
+  bool EmitVariableDecorations(ast::Variable* var);
 };
 
 }  // namespace wgsl
diff --git a/src/writer/wgsl/generator_impl_function_test.cc b/src/writer/wgsl/generator_impl_function_test.cc
index cbc0192..b9d3a0c 100644
--- a/src/writer/wgsl/generator_impl_function_test.cc
+++ b/src/writer/wgsl/generator_impl_function_test.cc
@@ -13,7 +13,6 @@
 // limitations under the License.
 
 #include "gtest/gtest.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/discard_statement.h"
 #include "src/ast/function.h"
 #include "src/ast/member_accessor_expression.h"
@@ -69,9 +68,21 @@
   ast::type::I32 i32;
   ast::VariableList params;
   params.push_back(
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32));
+      create<ast::Variable>(Source{},                         // source
+                            "a",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &f32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
   params.push_back(
-      create<ast::Variable>(Source{}, "b", ast::StorageClass::kNone, &i32));
+      create<ast::Variable>(Source{},                         // source
+                            "b",                              // name
+                            ast::StorageClass::kNone,         // storage_class
+                            &i32,                             // type
+                            false,                            // is_const
+                            nullptr,                          // constructor
+                            ast::VariableDecorationList{}));  // decorations
 
   ast::type::Void void_type;
   ast::Function func(Source{}, "my_func", params, &void_type, body,
@@ -191,13 +202,18 @@
   ast::type::Struct s("Data", str);
   ast::type::AccessControl ac(ast::AccessControl::kReadWrite, &s);
 
-  auto* data_var = create<ast::DecoratedVariable>(create<ast::Variable>(
-      Source{}, "data", ast::StorageClass::kStorageBuffer, &ac));
-
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(0, Source{}));
-  data_var->set_decorations(decos);
+  auto* data_var =
+      create<ast::Variable>(Source{},                           // source
+                            "data",                             // name
+                            ast::StorageClass::kStorageBuffer,  // storage_class
+                            &ac,                                // type
+                            false,                              // is_const
+                            nullptr,                            // constructor
+                            ast::VariableDecorationList{
+                                // decorations
+                                create<ast::BindingDecoration>(0, Source{}),
+                                create<ast::SetDecoration>(0, Source{}),
+                            });
 
   mod.AddConstructedType(&s);
 
@@ -206,11 +222,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
@@ -228,11 +249,16 @@
 
   {
     ast::VariableList params;
-    auto* var = create<ast::Variable>(Source{}, "v",
-                                      ast::StorageClass::kFunction, &f32);
-    var->set_constructor(create<ast::MemberAccessorExpression>(
-        create<ast::IdentifierExpression>("data"),
-        create<ast::IdentifierExpression>("d")));
+    auto* var = create<ast::Variable>(
+        Source{},                      // source
+        "v",                           // name
+        ast::StorageClass::kFunction,  // storage_class
+        &f32,                          // type
+        false,                         // is_const
+        create<ast::MemberAccessorExpression>(
+            create<ast::IdentifierExpression>("data"),
+            create<ast::IdentifierExpression>("d")),  // constructor
+        ast::VariableDecorationList{});               // decorations
 
     auto* body = create<ast::BlockStatement>();
     body->append(create<ast::VariableDeclStatement>(var));
diff --git a/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index cd25fb6..c892a2b 100644
--- a/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -33,7 +33,13 @@
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kNone, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kNone,        // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -49,7 +55,13 @@
   // https://github.com/gpuweb/gpuweb/issues/654
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kFunction, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kFunction,    // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
@@ -62,7 +74,13 @@
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
   ast::type::F32 f32;
   auto* var =
-      create<ast::Variable>(Source{}, "a", ast::StorageClass::kPrivate, &f32);
+      create<ast::Variable>(Source{},                        // source
+                            "a",                             // name
+                            ast::StorageClass::kPrivate,     // storage_class
+                            &f32,                            // type
+                            false,                           // is_const
+                            nullptr,                         // constructor
+                            ast::VariableDecorationList{});  // decorations
 
   ast::VariableDeclStatement stmt(var);
 
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index 05b3dde..6fcc325 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -18,10 +18,10 @@
 #include "src/ast/binding_decoration.h"
 #include "src/ast/builtin_decoration.h"
 #include "src/ast/constant_id_decoration.h"
-#include "src/ast/decorated_variable.h"
 #include "src/ast/location_decoration.h"
 #include "src/ast/set_decoration.h"
 #include "src/ast/type/f32_type.h"
+#include "src/ast/variable.h"
 #include "src/ast/variable_decoration.h"
 #include "src/writer/wgsl/generator_impl.h"
 #include "src/writer/wgsl/test_helper.h"
@@ -35,7 +35,8 @@
 
 TEST_F(WgslGeneratorImplTest, EmitVariable) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32);
+  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32, false, nullptr,
+                  ast::VariableDecorationList{});
 
   ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(gen.result(), R"(var a : f32;
@@ -44,7 +45,8 @@
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "a", ast::StorageClass::kInput, &f32);
+  ast::Variable v(Source{}, "a", ast::StorageClass::kInput, &f32, false,
+                  nullptr, ast::VariableDecorationList{});
 
   ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(gen.result(), R"(var<in> a : f32;
@@ -54,15 +56,12 @@
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(create<ast::LocationDecoration>(2, Source{}));
+  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32, false, nullptr,
+                  ast::VariableDecorationList{
+                      create<ast::LocationDecoration>(2, Source{}),
+                  });
 
-  ast::DecoratedVariable dv;
-  dv.set_name("a");
-  dv.set_type(&f32);
-  dv.set_decorations(decos);
-
-  ASSERT_TRUE(gen.EmitVariable(&dv)) << gen.error();
+  ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(gen.result(), R"([[location(2)]] var a : f32;
 )");
 }
@@ -70,20 +69,17 @@
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated_Multiple) {
   ast::type::F32 f32;
 
-  ast::VariableDecorationList decos;
-  decos.push_back(
-      create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}));
-  decos.push_back(create<ast::BindingDecoration>(0, Source{}));
-  decos.push_back(create<ast::SetDecoration>(1, Source{}));
-  decos.push_back(create<ast::LocationDecoration>(2, Source{}));
-  decos.push_back(create<ast::ConstantIdDecoration>(42, Source{}));
+  ast::Variable v(
+      Source{}, "a", ast::StorageClass::kNone, &f32, false, nullptr,
+      ast::VariableDecorationList{
+          create<ast::BuiltinDecoration>(ast::Builtin::kPosition, Source{}),
+          create<ast::BindingDecoration>(0, Source{}),
+          create<ast::SetDecoration>(1, Source{}),
+          create<ast::LocationDecoration>(2, Source{}),
+          create<ast::ConstantIdDecoration>(42, Source{}),
+      });
 
-  ast::DecoratedVariable dv;
-  dv.set_name("a");
-  dv.set_type(&f32);
-  dv.set_decorations(decos);
-
-  ASSERT_TRUE(gen.EmitVariable(&dv)) << gen.error();
+  ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(
       gen.result(),
       R"([[builtin(position), binding(0), set(1), location(2), constant_id(42)]] var a : f32;
@@ -94,8 +90,8 @@
   auto* ident = create<ast::IdentifierExpression>("initializer");
 
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32);
-  v.set_constructor(ident);
+  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32, false, ident,
+                  ast::VariableDecorationList{});
 
   ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(gen.result(), R"(var a : f32 = initializer;
@@ -106,9 +102,8 @@
   auto* ident = create<ast::IdentifierExpression>("initializer");
 
   ast::type::F32 f32;
-  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32);
-  v.set_constructor(ident);
-  v.set_is_const(true);
+  ast::Variable v(Source{}, "a", ast::StorageClass::kNone, &f32, true, ident,
+                  ast::VariableDecorationList{});
 
   ASSERT_TRUE(gen.EmitVariable(&v)) << gen.error();
   EXPECT_EQ(gen.result(), R"(const a : f32 = initializer;