wgsl: Deprecate [[access]] decorations

Handle access control on var declarations instead of via [[access]]
decorations. This change does the minimal work to migrate the WGSL
parser over to the new syntax. Additional changes will be needed
to correctly generate defaulted access qualifiers, as well as
validating access usage.

The [[access]] decorations are still supported by the WGSL parser,
with new deprecated warnings, but not for aliases. Example:
   var x : [[access(x)]] alias_to_struct;

Making this work is far more effort than I want to dedicate to backwards
compatibility, and I do not beleive any real-world usage will be doing
this.

Still TODO:
* Adding access control as the optional, third parameter to ptr<>.
* Calculating default accesses for the various storage types.
* Validating usage of variables against the different accesses.

Bug: tint:846
Change-Id: If8ca82e5d16ec319ecd01f9a2cafffd930963bde
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/53088
Commit-Queue: Ben Clayton <bclayton@google.com>
Reviewed-by: James Price <jrprice@google.com>
Reviewed-by: David Neto <dneto@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
diff --git a/docs/diagnostics_guide.md b/docs/diagnostics_guide.md
index 00cdf41..b5def90 100644
--- a/docs/diagnostics_guide.md
+++ b/docs/diagnostics_guide.md
@@ -96,21 +96,21 @@
 **Don't:**
 
 ```
-shader.wgsl:7:1 error: the originating variable of the left-hand side must not have an access(read) access attribute.
+shader.wgsl:7:1 error: the originating variable of the left-hand side of an assignment expression must not be declared with read access control.
 ```
 
 **Do:**
 
 ```
-shader.wgsl:7:1 error: cannot assign to variable with [[access(read)]] decoration
+shader.wgsl:7:1 error: cannot assign to variable with read access control
 
-x = 1;
-^
+x.y = 1;
+^^^^^^^
 
-shader.wgsl:2:8 note: [[access(read)]] declared here
+shader.wgsl:2:8 note: read access control declared here
 
-var x : [[access(read)]] i32;
-        ^^^^^^^^^^^^^^^^
+var<storage, read> x : i32;
+             ^^^^
 ```
 
 **Justification:**
diff --git a/fuzzers/tint_common_fuzzer.cc b/fuzzers/tint_common_fuzzer.cc
index 38d4a7c..6bebfe8 100644
--- a/fuzzers/tint_common_fuzzer.cc
+++ b/fuzzers/tint_common_fuzzer.cc
@@ -101,20 +101,19 @@
     uint8_t old_binding;
     uint8_t new_group;
     uint8_t new_binding;
-    ast::AccessControl::Access new_ac;
+    ast::Access new_access;
   };
 
   std::vector<Config> configs = r->vector<Config>();
   transform::BindingRemapper::BindingPoints binding_points;
-  transform::BindingRemapper::AccessControls access_controls;
+  transform::BindingRemapper::Accesses accesses;
   for (const auto& config : configs) {
     binding_points[{config.old_binding, config.old_group}] = {
         config.new_binding, config.new_group};
-    access_controls[{config.old_binding, config.old_group}] = config.new_ac;
+    accesss[{config.old_binding, config.old_group}] = config.new_access;
   }
 
-  inputs->Add<transform::BindingRemapper::Remappings>(binding_points,
-                                                      access_controls);
+  inputs->Add<transform::BindingRemapper::Remappings>(binding_points, accesss);
 }
 
 void ExtractFirstIndexOffsetInputs(Reader* r,
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 9498f0a..57b816d 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -292,8 +292,8 @@
 
 libtint_source_set("libtint_core_all_src") {
   sources = [
-    "ast/access_control.cc",
-    "ast/access_control.h",
+    "ast/access.cc",
+    "ast/access.h",
     "ast/access_decoration.cc",
     "ast/access_decoration.h",
     "ast/alias.cc",
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 268b037..16d5a90 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -38,8 +38,8 @@
 
 set(TINT_LIB_SRCS
   ../include/tint/tint.h
-  ast/access_control.cc
-  ast/access_control.h
+  ast/access.cc
+  ast/access.h
   ast/access_decoration.cc
   ast/access_decoration.h
   ast/alias.cc
@@ -496,7 +496,6 @@
 
 if(${TINT_BUILD_TESTS})
   set(TINT_TEST_SRCS
-    ast/access_control_test.cc
     ast/access_decoration_test.cc
     ast/alias_test.cc
     ast/array_accessor_expression_test.cc
@@ -748,7 +747,7 @@
       reader/wgsl/parser_impl_variable_decoration_test.cc
       reader/wgsl/parser_impl_variable_ident_decl_test.cc
       reader/wgsl/parser_impl_variable_stmt_test.cc
-      reader/wgsl/parser_impl_variable_storage_decoration_test.cc
+      reader/wgsl/parser_impl_variable_qualifier_test.cc
       reader/wgsl/token_test.cc
     )
   endif()
diff --git a/src/ast/access.cc b/src/ast/access.cc
new file mode 100644
index 0000000..a95753f
--- /dev/null
+++ b/src/ast/access.cc
@@ -0,0 +1,43 @@
+// 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/access.h"
+
+namespace tint {
+namespace ast {
+
+std::ostream& operator<<(std::ostream& out, Access access) {
+  switch (access) {
+    case ast::Access::kUndefined: {
+      out << "undefined";
+      break;
+    }
+    case ast::Access::kRead: {
+      out << "read";
+      break;
+    }
+    case ast::Access::kReadWrite: {
+      out << "read_write";
+      break;
+    }
+    case ast::Access::kWrite: {
+      out << "write";
+      break;
+    }
+  }
+  return out;
+}
+
+}  // namespace ast
+}  // namespace tint
diff --git a/src/ast/access.h b/src/ast/access.h
new file mode 100644
index 0000000..1faddbf
--- /dev/null
+++ b/src/ast/access.h
@@ -0,0 +1,47 @@
+// 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_ACCESS_H_
+#define SRC_AST_ACCESS_H_
+
+#include <ostream>
+#include <string>
+
+namespace tint {
+namespace ast {
+
+/// The access control settings
+enum Access {
+  /// Not declared in the source
+  kUndefined,
+  /// Read only
+  kRead,
+  /// Write only
+  kWrite,
+  /// Read write
+  kReadWrite
+};
+
+/// @param out the std::ostream to write to
+/// @param access the Access
+/// @return the std::ostream so calls can be chained
+std::ostream& operator<<(std::ostream& out, Access access);
+
+/// [DEPRECATED]: Old name in use by Dawn.
+using AccessControl = Access;
+
+}  // namespace ast
+}  // namespace tint
+
+#endif  // SRC_AST_ACCESS_H_
diff --git a/src/ast/access_control.cc b/src/ast/access_control.cc
deleted file mode 100644
index ad86d2c..0000000
--- a/src/ast/access_control.cc
+++ /dev/null
@@ -1,97 +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/access_control.h"
-
-#include "src/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::AccessControl);
-
-namespace tint {
-namespace ast {
-
-AccessControl::AccessControl(ProgramID program_id,
-                             const Source& source,
-                             Access access,
-                             const Type* subtype)
-    : Base(program_id, source), access_(access), subtype_(subtype) {
-  TINT_ASSERT(subtype_);
-  TINT_ASSERT(!subtype_->Is<AccessControl>());
-}
-
-AccessControl::AccessControl(AccessControl&&) = default;
-
-AccessControl::~AccessControl() = default;
-
-std::string AccessControl::type_name() const {
-  std::string name = "__access_control_";
-  switch (access_) {
-    case ast::AccessControl::kRead:
-      name += "read_only";
-      break;
-    case ast::AccessControl::kWrite:
-      name += "write_only";
-      break;
-    case ast::AccessControl::kReadWrite:
-      name += "read_write";
-      break;
-  }
-  return name + subtype_->type_name();
-}
-
-std::string AccessControl::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "[[access(";
-  switch (access_) {
-    case ast::AccessControl::kRead:
-      out << "read";
-      break;
-    case ast::AccessControl::kWrite:
-      out << "write";
-      break;
-    case ast::AccessControl::kReadWrite:
-      out << "read_write";
-      break;
-  }
-  out << ")]] " << subtype_->FriendlyName(symbols);
-  return out.str();
-}
-
-AccessControl* AccessControl::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source());
-  auto* ty = ctx->Clone(type());
-  return ctx->dst->create<AccessControl>(src, access_, ty);
-}
-
-std::ostream& operator<<(std::ostream& out, AccessControl::Access access) {
-  switch (access) {
-    case ast::AccessControl::kRead: {
-      out << "read_only";
-      break;
-    }
-    case ast::AccessControl::kReadWrite: {
-      out << "read_write";
-      break;
-    }
-    case ast::AccessControl::kWrite: {
-      out << "write_only";
-      break;
-    }
-  }
-  return out;
-}
-
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/access_control.h b/src/ast/access_control.h
deleted file mode 100644
index 705faca..0000000
--- a/src/ast/access_control.h
+++ /dev/null
@@ -1,90 +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_ACCESS_CONTROL_H_
-#define SRC_AST_ACCESS_CONTROL_H_
-
-#include <ostream>
-#include <string>
-
-#include "src/ast/type.h"
-
-namespace tint {
-namespace ast {
-
-/// An access control type. Holds an access setting and pointer to another type.
-class AccessControl : public Castable<AccessControl, Type> {
- public:
-  /// The access control settings
-  enum Access {
-    /// Read only
-    kRead,
-    /// Write only
-    kWrite,
-    /// Read write
-    kReadWrite
-  };
-
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the source of this node
-  /// @param access the access control setting
-  /// @param subtype the access controlled type
-  AccessControl(ProgramID program_id,
-                const Source& source,
-                Access access,
-                const Type* subtype);
-  /// Move constructor
-  AccessControl(AccessControl&&);
-  ~AccessControl() override;
-
-  /// @returns true if the access control is read only
-  bool IsReadOnly() const { return access_ == Access::kRead; }
-  /// @returns true if the access control is write only
-  bool IsWriteOnly() const { return access_ == Access::kWrite; }
-  /// @returns true if the access control is read/write
-  bool IsReadWrite() const { return access_ == Access::kReadWrite; }
-
-  /// @returns the access control value
-  Access access_control() const { return access_; }
-  /// @returns the subtype type
-  Type* type() const { return const_cast<Type*>(subtype_); }
-
-  /// @returns the name for this type
-  std::string type_name() const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  AccessControl* Clone(CloneContext* ctx) const override;
-
- private:
-  Access const access_;
-  const Type* const subtype_;
-};
-
-/// @param out the std::ostream to write to
-/// @param access the AccessControl
-/// @return the std::ostream so calls can be chained
-std::ostream& operator<<(std::ostream& out, AccessControl::Access access);
-
-}  // namespace ast
-}  // namespace tint
-
-#endif  // SRC_AST_ACCESS_CONTROL_H_
diff --git a/src/ast/access_control_test.cc b/src/ast/access_control_test.cc
deleted file mode 100644
index d8fca38..0000000
--- a/src/ast/access_control_test.cc
+++ /dev/null
@@ -1,94 +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/access_control.h"
-
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
-#include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
-
-namespace tint {
-namespace ast {
-namespace {
-
-using AstAccessControlTest = TestHelper;
-
-TEST_F(AstAccessControlTest, Create) {
-  auto* u32 = create<U32>();
-  auto* a = create<AccessControl>(AccessControl::kReadWrite, u32);
-  EXPECT_TRUE(a->IsReadWrite());
-  EXPECT_EQ(a->type(), u32);
-}
-
-TEST_F(AstAccessControlTest, AccessRead) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kRead, i32);
-  EXPECT_TRUE(ac->IsReadOnly());
-  EXPECT_FALSE(ac->IsWriteOnly());
-  EXPECT_FALSE(ac->IsReadWrite());
-
-  EXPECT_EQ(ac->type_name(), "__access_control_read_only__i32");
-}
-
-TEST_F(AstAccessControlTest, AccessWrite) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kWrite, i32);
-  EXPECT_FALSE(ac->IsReadOnly());
-  EXPECT_TRUE(ac->IsWriteOnly());
-  EXPECT_FALSE(ac->IsReadWrite());
-
-  EXPECT_EQ(ac->type_name(), "__access_control_write_only__i32");
-}
-
-TEST_F(AstAccessControlTest, AccessReadWrite) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kReadWrite, i32);
-  EXPECT_FALSE(ac->IsReadOnly());
-  EXPECT_FALSE(ac->IsWriteOnly());
-  EXPECT_TRUE(ac->IsReadWrite());
-
-  EXPECT_EQ(ac->type_name(), "__access_control_read_write__i32");
-}
-
-TEST_F(AstAccessControlTest, FriendlyNameReadOnly) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kRead, i32);
-  EXPECT_EQ(ac->FriendlyName(Symbols()), "[[access(read)]] i32");
-}
-
-TEST_F(AstAccessControlTest, FriendlyNameWriteOnly) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kWrite, i32);
-  EXPECT_EQ(ac->FriendlyName(Symbols()), "[[access(write)]] i32");
-}
-
-TEST_F(AstAccessControlTest, FriendlyNameReadWrite) {
-  auto* i32 = create<I32>();
-  auto* ac = create<AccessControl>(AccessControl::kReadWrite, i32);
-  EXPECT_EQ(ac->FriendlyName(Symbols()), "[[access(read_write)]] i32");
-}
-
-}  // namespace
-}  // namespace ast
-}  // namespace tint
diff --git a/src/ast/access_decoration.cc b/src/ast/access_decoration.cc
index e00ace6..865422a 100644
--- a/src/ast/access_decoration.cc
+++ b/src/ast/access_decoration.cc
@@ -23,7 +23,7 @@
 
 AccessDecoration::AccessDecoration(ProgramID program_id,
                                    const Source& source,
-                                   AccessControl::Access val)
+                                   Access val)
     : Base(program_id, source), value_(val) {}
 
 AccessDecoration::~AccessDecoration() = default;
diff --git a/src/ast/access_decoration.h b/src/ast/access_decoration.h
index 894bb69..2b385e9 100644
--- a/src/ast/access_decoration.h
+++ b/src/ast/access_decoration.h
@@ -15,26 +15,25 @@
 #ifndef SRC_AST_ACCESS_DECORATION_H_
 #define SRC_AST_ACCESS_DECORATION_H_
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/decoration.h"
 
 namespace tint {
 namespace ast {
 
 /// An access decoration
+/// [DEPRECATED]: TODO(crbug.com/tint/846): Remove this class
 class AccessDecoration : public Castable<AccessDecoration, Decoration> {
  public:
   /// constructor
   /// @param program_id the identifier of the program that owns this node
   /// @param source the source of this decoration
   /// @param value the access value
-  AccessDecoration(ProgramID program_id,
-                   const Source& source,
-                   AccessControl::Access value);
+  AccessDecoration(ProgramID program_id, const Source& source, Access value);
   ~AccessDecoration() override;
 
   /// @returns the access control value
-  AccessControl::Access value() const { return value_; }
+  Access value() const { return value_; }
 
   /// Outputs the decoration to the given stream
   /// @param sem the semantic info for the program
@@ -51,7 +50,7 @@
   AccessDecoration* Clone(CloneContext* ctx) const override;
 
  private:
-  AccessControl::Access const value_;
+  Access const value_;
 };
 
 }  // namespace ast
diff --git a/src/ast/access_decoration_test.cc b/src/ast/access_decoration_test.cc
index 047b170..ecb6e0d 100644
--- a/src/ast/access_decoration_test.cc
+++ b/src/ast/access_decoration_test.cc
@@ -23,13 +23,13 @@
 using AccessDecorationTest = TestHelper;
 
 TEST_F(AccessDecorationTest, Creation) {
-  auto* d = create<AccessDecoration>(ast::AccessControl::kWrite);
-  EXPECT_EQ(ast::AccessControl::kWrite, d->value());
+  auto* d = create<AccessDecoration>(ast::Access::kWrite);
+  EXPECT_EQ(ast::Access::kWrite, d->value());
 }
 
 TEST_F(AccessDecorationTest, ToStr) {
-  auto* d = create<AccessDecoration>(ast::AccessControl::kRead);
-  EXPECT_EQ(str(d), R"(AccessDecoration{read_only}
+  auto* d = create<AccessDecoration>(ast::Access::kRead);
+  EXPECT_EQ(str(d), R"(AccessDecoration{read}
 )");
 }
 
diff --git a/src/ast/alias_test.cc b/src/ast/alias_test.cc
index 1dc9710..9adebbd 100644
--- a/src/ast/alias_test.cc
+++ b/src/ast/alias_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/ast/alias.h"
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/array.h"
 #include "src/ast/bool.h"
 #include "src/ast/f32.h"
@@ -76,23 +76,6 @@
   EXPECT_EQ(aapaa->UnwrapAll(), u32);
 }
 
-TEST_F(AstAliasTest, UnwrapAll_AccessControlPointer) {
-  auto* u32 = create<U32>();
-  auto* a = create<AccessControl>(AccessControl::kRead, u32);
-  auto* pa = create<Pointer>(a, StorageClass::kUniform);
-  EXPECT_EQ(pa->type(), a);
-  EXPECT_EQ(pa->UnwrapAll(), u32);
-}
-
-TEST_F(AstAliasTest, UnwrapAll_PointerAccessControl) {
-  auto* u32 = create<U32>();
-  auto* p = create<Pointer>(u32, StorageClass::kUniform);
-  auto* a = create<AccessControl>(AccessControl::kRead, p);
-
-  EXPECT_EQ(a->type(), p);
-  EXPECT_EQ(a->UnwrapAll(), u32);
-}
-
 }  // namespace
 }  // namespace ast
 }  // namespace tint
diff --git a/src/ast/array_test.cc b/src/ast/array_test.cc
index dac1542..5e8b9c8 100644
--- a/src/ast/array_test.cc
+++ b/src/ast/array_test.cc
@@ -13,19 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/array.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/ast_type.cc b/src/ast/ast_type.cc
index a9ea9d1..6702bd9 100644
--- a/src/ast/ast_type.cc
+++ b/src/ast/ast_type.cc
@@ -14,7 +14,6 @@
 
 #include "src/ast/type.h"
 
-#include "src/ast/access_control.h"
 #include "src/ast/alias.h"
 #include "src/ast/bool.h"
 #include "src/ast/f32.h"
@@ -43,8 +42,6 @@
   while (true) {
     if (auto* alias = type->As<Alias>()) {
       type = alias->type();
-    } else if (auto* access = type->As<AccessControl>()) {
-      type = access->type();
     } else if (auto* ptr = type->As<Pointer>()) {
       type = ptr->type();
     } else {
diff --git a/src/ast/bool_test.cc b/src/ast/bool_test.cc
index d1668c7..7c8a32e 100644
--- a/src/ast/bool_test.cc
+++ b/src/ast/bool_test.cc
@@ -13,19 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/bool.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/depth_texture_test.cc b/src/ast/depth_texture_test.cc
index a018e4a..d7b7249 100644
--- a/src/ast/depth_texture_test.cc
+++ b/src/ast/depth_texture_test.cc
@@ -13,22 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/depth_texture.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampled_texture.h"
-#include "src/ast/sampler.h"
-#include "src/ast/storage_texture.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/external_texture_test.cc b/src/ast/external_texture_test.cc
index b8d75d1..ff11eae 100644
--- a/src/ast/external_texture_test.cc
+++ b/src/ast/external_texture_test.cc
@@ -14,22 +14,7 @@
 
 #include "src/ast/external_texture.h"
 
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/depth_texture.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/storage_texture.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/f32_test.cc b/src/ast/f32_test.cc
index 220af9d..12eeec8 100644
--- a/src/ast/f32_test.cc
+++ b/src/ast/f32_test.cc
@@ -13,19 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/f32.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/function_test.cc b/src/ast/function_test.cc
index a634e6f..61ee8a6 100644
--- a/src/ast/function_test.cc
+++ b/src/ast/function_test.cc
@@ -189,6 +189,7 @@
   VariableConst{
     var
     none
+    undefined
     __i32
   }
 )
diff --git a/src/ast/i32_test.cc b/src/ast/i32_test.cc
index 5f1ae0a..6c224ca 100644
--- a/src/ast/i32_test.cc
+++ b/src/ast/i32_test.cc
@@ -14,19 +14,7 @@
 
 #include "src/ast/i32.h"
 
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/intrinsic_texture_helper_test.cc b/src/ast/intrinsic_texture_helper_test.cc
index 82cf623..f5af1fb 100644
--- a/src/ast/intrinsic_texture_helper_test.cc
+++ b/src/ast/intrinsic_texture_helper_test.cc
@@ -62,7 +62,7 @@
 TextureOverloadCase::TextureOverloadCase(
     ValidTextureOverload o,
     const char* d,
-    AccessControl::Access access,
+    Access acc,
     ast::ImageFormat i,
     ast::TextureDimension dims,
     TextureDataType datatype,
@@ -71,7 +71,7 @@
     : overload(o),
       description(d),
       texture_kind(TextureKind::kStorage),
-      access_control(access),
+      access(acc),
       image_format(i),
       texture_dimension(dims),
       texture_data_type(datatype),
@@ -124,7 +124,7 @@
     out << "<unused>";
   }
   out << "\n";
-  out << "access_control:    " << data.access_control << "\n";
+  out << "access:    " << data.access << "\n";
   out << "image_format:      " << data.image_format << "\n";
   out << "texture_dimension: " << data.texture_dimension << "\n";
   out << "texture_data_type: " << data.texture_data_type << "\n";
@@ -157,23 +157,22 @@
       return b->Global("texture",
                        b->ty.sampled_texture(texture_dimension,
                                              buildResultVectorComponentType(b)),
-                       ast::StorageClass::kNone, nullptr, decos);
+                       decos);
 
     case ast::intrinsic::test::TextureKind::kDepth:
       return b->Global("texture", b->ty.depth_texture(texture_dimension),
-                       ast::StorageClass::kNone, nullptr, decos);
+                       decos);
 
     case ast::intrinsic::test::TextureKind::kMultisampled:
       return b->Global(
           "texture",
           b->ty.multisampled_texture(texture_dimension,
                                      buildResultVectorComponentType(b)),
-          ast::StorageClass::kNone, nullptr, decos);
+          decos);
 
     case ast::intrinsic::test::TextureKind::kStorage: {
-      auto* st = b->ty.storage_texture(texture_dimension, image_format);
-      auto* ac = b->ty.access(access_control, st);
-      return b->Global("texture", ac, ast::StorageClass::kNone, nullptr, decos);
+      auto* st = b->ty.storage_texture(texture_dimension, image_format, access);
+      return b->Global("texture", st, decos);
     }
   }
 
@@ -187,8 +186,7 @@
       b->create<ast::GroupDecoration>(0),
       b->create<ast::BindingDecoration>(1),
   };
-  return b->Global("sampler", b->ty.sampler(sampler_kind),
-                   ast::StorageClass::kNone, nullptr, decos);
+  return b->Global("sampler", b->ty.sampler(sampler_kind), decos);
 }
 
 std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
@@ -405,7 +403,7 @@
       {
           ValidTextureOverload::kDimensionsStorageRO1d,
           "textureDimensions(t : texture_storage_1d<rgba32float>) -> i32",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k1d,
           TextureDataType::kF32,
@@ -416,7 +414,7 @@
           ValidTextureOverload::kDimensionsStorageRO2d,
           "textureDimensions(t : texture_storage_2d<rgba32float>) -> "
           "vec2<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -427,7 +425,7 @@
           ValidTextureOverload::kDimensionsStorageRO2dArray,
           "textureDimensions(t : texture_storage_2d_array<rgba32float>) -> "
           "vec2<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2dArray,
           TextureDataType::kF32,
@@ -438,7 +436,7 @@
           ValidTextureOverload::kDimensionsStorageRO3d,
           "textureDimensions(t : texture_storage_3d<rgba32float>) -> "
           "vec3<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k3d,
           TextureDataType::kF32,
@@ -448,7 +446,7 @@
       {
           ValidTextureOverload::kDimensionsStorageWO1d,
           "textureDimensions(t : texture_storage_1d<rgba32float>) -> i32",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k1d,
           TextureDataType::kF32,
@@ -459,7 +457,7 @@
           ValidTextureOverload::kDimensionsStorageWO2d,
           "textureDimensions(t : texture_storage_2d<rgba32float>) -> "
           "vec2<i32>",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -470,7 +468,7 @@
           ValidTextureOverload::kDimensionsStorageWO2dArray,
           "textureDimensions(t : texture_storage_2d_array<rgba32float>) -> "
           "vec2<i32>",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2dArray,
           TextureDataType::kF32,
@@ -481,7 +479,7 @@
           ValidTextureOverload::kDimensionsStorageWO3d,
           "textureDimensions(t : texture_storage_3d<rgba32float>) -> "
           "vec3<i32>",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k3d,
           TextureDataType::kF32,
@@ -531,7 +529,7 @@
       {
           ValidTextureOverload::kNumLayersStorageWO2dArray,
           "textureNumLayers(t : texture_storage_2d_array<rgba32float>) -> i32",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2dArray,
           TextureDataType::kF32,
@@ -1887,7 +1885,7 @@
           ValidTextureOverload::kLoadStorageRO1dRgba32float,
           "textureLoad(t      : texture_storage_1d<rgba32float>,\n"
           "            coords : i32) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k1d,
           TextureDataType::kF32,
@@ -1901,7 +1899,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba8unorm,
           "textureLoad(t           : texture_storage_2d<rgba8unorm>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba8Unorm,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -1915,7 +1913,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba8snorm,
           "textureLoad(t           : texture_storage_2d<rgba8snorm>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba8Snorm,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -1929,7 +1927,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba8uint,
           "textureLoad(t           : texture_storage_2d<rgba8uint>,\n"
           "            coords      : vec2<i32>) -> vec4<u32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba8Uint,
           ast::TextureDimension::k2d,
           TextureDataType::kU32,
@@ -1943,7 +1941,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba8sint,
           "textureLoad(t           : texture_storage_2d<rgba8sint>,\n"
           "            coords      : vec2<i32>) -> vec4<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba8Sint,
           ast::TextureDimension::k2d,
           TextureDataType::kI32,
@@ -1957,7 +1955,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba16uint,
           "textureLoad(t           : texture_storage_2d<rgba16uint>,\n"
           "            coords      : vec2<i32>) -> vec4<u32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba16Uint,
           ast::TextureDimension::k2d,
           TextureDataType::kU32,
@@ -1971,7 +1969,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba16sint,
           "textureLoad(t           : texture_storage_2d<rgba16sint>,\n"
           "            coords      : vec2<i32>) -> vec4<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba16Sint,
           ast::TextureDimension::k2d,
           TextureDataType::kI32,
@@ -1985,7 +1983,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba16float,
           "textureLoad(t           : texture_storage_2d<rgba16float>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba16Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -1999,7 +1997,7 @@
           ValidTextureOverload::kLoadStorageRO2dR32uint,
           "textureLoad(t           : texture_storage_2d<r32uint>,\n"
           "            coords      : vec2<i32>) -> vec4<u32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kR32Uint,
           ast::TextureDimension::k2d,
           TextureDataType::kU32,
@@ -2013,7 +2011,7 @@
           ValidTextureOverload::kLoadStorageRO2dR32sint,
           "textureLoad(t           : texture_storage_2d<r32sint>,\n"
           "            coords      : vec2<i32>) -> vec4<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kR32Sint,
           ast::TextureDimension::k2d,
           TextureDataType::kI32,
@@ -2027,7 +2025,7 @@
           ValidTextureOverload::kLoadStorageRO2dR32float,
           "textureLoad(t           : texture_storage_2d<r32float>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kR32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -2041,7 +2039,7 @@
           ValidTextureOverload::kLoadStorageRO2dRg32uint,
           "textureLoad(t           : texture_storage_2d<rg32uint>,\n"
           "            coords      : vec2<i32>) -> vec4<u32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRg32Uint,
           ast::TextureDimension::k2d,
           TextureDataType::kU32,
@@ -2055,7 +2053,7 @@
           ValidTextureOverload::kLoadStorageRO2dRg32sint,
           "textureLoad(t           : texture_storage_2d<rg32sint>,\n"
           "            coords      : vec2<i32>) -> vec4<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRg32Sint,
           ast::TextureDimension::k2d,
           TextureDataType::kI32,
@@ -2069,7 +2067,7 @@
           ValidTextureOverload::kLoadStorageRO2dRg32float,
           "textureLoad(t           : texture_storage_2d<rg32float>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRg32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -2083,7 +2081,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba32uint,
           "textureLoad(t           : texture_storage_2d<rgba32uint>,\n"
           "            coords      : vec2<i32>) -> vec4<u32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Uint,
           ast::TextureDimension::k2d,
           TextureDataType::kU32,
@@ -2097,7 +2095,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba32sint,
           "textureLoad(t           : texture_storage_2d<rgba32sint>,\n"
           "            coords      : vec2<i32>) -> vec4<i32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Sint,
           ast::TextureDimension::k2d,
           TextureDataType::kI32,
@@ -2111,7 +2109,7 @@
           ValidTextureOverload::kLoadStorageRO2dRgba32float,
           "textureLoad(t           : texture_storage_2d<rgba32float>,\n"
           "            coords      : vec2<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -2127,7 +2125,7 @@
           "texture_storage_2d_array<rgba32float>,\n"
           "            coords      : vec2<i32>,\n"
           "            array_index : i32) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2dArray,
           TextureDataType::kF32,
@@ -2142,7 +2140,7 @@
           ValidTextureOverload::kLoadStorageRO3dRgba32float,
           "textureLoad(t      : texture_storage_3d<rgba32float>,\n"
           "            coords : vec3<i32>) -> vec4<f32>",
-          ast::AccessControl::kRead,
+          ast::Access::kRead,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k3d,
           TextureDataType::kF32,
@@ -2157,7 +2155,7 @@
           "textureStore(t      : texture_storage_1d<rgba32float>,\n"
           "             coords : i32,\n"
           "             value  : vec4<T>)",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k1d,
           TextureDataType::kF32,
@@ -2173,7 +2171,7 @@
           "textureStore(t      : texture_storage_2d<rgba32float>,\n"
           "             coords : vec2<i32>,\n"
           "             value  : vec4<T>)",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2d,
           TextureDataType::kF32,
@@ -2190,7 +2188,7 @@
           "             coords      : vec2<i32>,\n"
           "             array_index : i32,\n"
           "             value       : vec4<T>)",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k2dArray,
           TextureDataType::kF32,
@@ -2207,7 +2205,7 @@
           "textureStore(t      : texture_storage_3d<rgba32float>,\n"
           "             coords : vec3<i32>,\n"
           "             value  : vec4<T>)",
-          ast::AccessControl::kWrite,
+          ast::Access::kWrite,
           ast::ImageFormat::kRgba32Float,
           ast::TextureDimension::k3d,
           TextureDataType::kF32,
diff --git a/src/ast/intrinsic_texture_helper_test.h b/src/ast/intrinsic_texture_helper_test.h
index 2151e47..38cc277 100644
--- a/src/ast/intrinsic_texture_helper_test.h
+++ b/src/ast/intrinsic_texture_helper_test.h
@@ -17,7 +17,7 @@
 
 #include <vector>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/program_builder.h"
 #include "src/sem/storage_texture_type.h"
 
@@ -192,7 +192,7 @@
   /// Constructor for textureLoad() with storage textures
   TextureOverloadCase(ValidTextureOverload,
                       const char*,
-                      AccessControl::Access,
+                      Access,
                       ast::ImageFormat,
                       ast::TextureDimension,
                       TextureDataType,
@@ -230,7 +230,7 @@
   ast::SamplerKind const sampler_kind = ast::SamplerKind::kSampler;
   /// The access control for the storage texture
   /// Used only when texture_kind is kStorage
-  AccessControl::Access const access_control = AccessControl::kReadWrite;
+  Access const access = Access::kReadWrite;
   /// The image format for the storage texture
   /// Used only when texture_kind is kStorage
   ast::ImageFormat const image_format = ast::ImageFormat::kNone;
diff --git a/src/ast/matrix_test.cc b/src/ast/matrix_test.cc
index 38b5f23..30b14a1 100644
--- a/src/ast/matrix_test.cc
+++ b/src/ast/matrix_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/ast/matrix.h"
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/alias.h"
 #include "src/ast/array.h"
 #include "src/ast/bool.h"
diff --git a/src/ast/module_clone_test.cc b/src/ast/module_clone_test.cc
index a1f4920..37a1129 100644
--- a/src/ast/module_clone_test.cc
+++ b/src/ast/module_clone_test.cc
@@ -42,15 +42,15 @@
 var<private> g0 : u32 = 20u;
 var<private> g1 : f32 = 123.0;
 [[group(0), binding(0)]] var g2 : texture_2d<f32>;
-[[group(1), binding(0)]] var g3 : [[access(read)]] texture_storage_2d<r32uint>;
-[[group(2), binding(0)]] var g4 : [[access(write)]] texture_storage_2d<rg32float>;
-[[group(3), binding(0)]] var g5 : [[access(read)]] texture_storage_2d<r32uint>;
-[[group(4), binding(0)]] var g6 : [[access(write)]] texture_storage_2d<rg32float>;
+[[group(1), binding(0)]] var g3 : texture_storage_2d<r32uint, read>;
+[[group(2), binding(0)]] var g4 : texture_storage_2d<rg32float, write>;
+[[group(3), binding(0)]] var g5 : texture_storage_2d<r32uint, read>;
+[[group(4), binding(0)]] var g6 : texture_storage_2d<rg32float, write>;
 
 var<private> g7 : vec3<f32>;
-[[group(0), binding(1)]] var<storage> g8 : [[access(write)]] S;
-[[group(1), binding(1)]] var<storage> g9 : [[access(read)]] S;
-[[group(2), binding(1)]] var<storage> g10 : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, write> g8 : S;
+[[group(1), binding(1)]] var<storage, read> g9 : S;
+[[group(2), binding(1)]] var<storage, read_write> g10 : S;
 
 fn f0(p0 : bool) -> f32 {
   if (p0) {
diff --git a/src/ast/multisampled_texture_test.cc b/src/ast/multisampled_texture_test.cc
index a4c55d9..5671f1e 100644
--- a/src/ast/multisampled_texture_test.cc
+++ b/src/ast/multisampled_texture_test.cc
@@ -14,7 +14,7 @@
 
 #include "src/ast/multisampled_texture.h"
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/alias.h"
 #include "src/ast/array.h"
 #include "src/ast/bool.h"
diff --git a/src/ast/pointer_test.cc b/src/ast/pointer_test.cc
index 6d0104f..d2eaa9e 100644
--- a/src/ast/pointer_test.cc
+++ b/src/ast/pointer_test.cc
@@ -13,19 +13,9 @@
 // limitations under the License.
 
 #include "src/ast/pointer.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
+
 #include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/sampled_texture_test.cc b/src/ast/sampled_texture_test.cc
index 6c94c0c..35e932e 100644
--- a/src/ast/sampled_texture_test.cc
+++ b/src/ast/sampled_texture_test.cc
@@ -14,22 +14,8 @@
 
 #include "src/ast/sampled_texture.h"
 
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/depth_texture.h"
 #include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/storage_texture.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/sampler_test.cc b/src/ast/sampler_test.cc
index 339e6fa..186eb48 100644
--- a/src/ast/sampler_test.cc
+++ b/src/ast/sampler_test.cc
@@ -13,19 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/sampler.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/storage_texture.cc b/src/ast/storage_texture.cc
index f1f23d6..38207de 100644
--- a/src/ast/storage_texture.cc
+++ b/src/ast/storage_texture.cc
@@ -144,8 +144,12 @@
                                const Source& source,
                                TextureDimension dim,
                                ImageFormat format,
-                               Type* subtype)
-    : Base(program_id, source, dim), image_format_(format), subtype_(subtype) {}
+                               Type* subtype,
+                               Access access)
+    : Base(program_id, source, dim),
+      image_format_(format),
+      subtype_(subtype),
+      access_(access) {}
 
 StorageTexture::StorageTexture(StorageTexture&&) = default;
 
@@ -153,13 +157,15 @@
 
 std::string StorageTexture::type_name() const {
   std::ostringstream out;
-  out << "__storage_texture_" << dim() << "_" << image_format_;
+  out << "__storage_texture_" << dim() << "_" << image_format_ << "_"
+      << access_;
   return out.str();
 }
 
 std::string StorageTexture::FriendlyName(const SymbolTable&) const {
   std::ostringstream out;
-  out << "texture_storage_" << dim() << "<" << image_format_ << ">";
+  out << "texture_storage_" << dim() << "<" << image_format_ << ", " << access_
+      << ">";
   return out.str();
 }
 
@@ -167,7 +173,8 @@
   // Clone arguments outside of create() call to have deterministic ordering
   auto src = ctx->Clone(source());
   auto* ty = ctx->Clone(type());
-  return ctx->dst->create<StorageTexture>(src, dim(), image_format_, ty);
+  return ctx->dst->create<StorageTexture>(src, dim(), image_format(), ty,
+                                          access());
 }
 
 Type* StorageTexture::SubtypeFor(ImageFormat format, ProgramBuilder& builder) {
diff --git a/src/ast/storage_texture.h b/src/ast/storage_texture.h
index bdf16b3..9d45b95 100644
--- a/src/ast/storage_texture.h
+++ b/src/ast/storage_texture.h
@@ -17,6 +17,7 @@
 
 #include <string>
 
+#include "src/ast/access.h"
 #include "src/ast/texture.h"
 
 namespace tint {
@@ -78,21 +79,33 @@
   /// @param dim the dimensionality of the texture
   /// @param format the image format of the texture
   /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
+  /// @param access_control the access control for the texture.
   StorageTexture(ProgramID program_id,
                  const Source& source,
                  TextureDimension dim,
                  ImageFormat format,
-                 Type* subtype);
+                 Type* subtype,
+                 Access access_control);
 
   /// Move constructor
   StorageTexture(StorageTexture&&);
   ~StorageTexture() override;
 
+  /// @returns the image format
+  ImageFormat image_format() const { return image_format_; }
+
   /// @returns the storage subtype
   Type* type() const { return subtype_; }
 
-  /// @returns the image format
-  ImageFormat image_format() const { return image_format_; }
+  /// @returns the access control
+  Access access() const { return access_; }
+
+  /// @returns true if the access control is read only
+  bool is_read_only() const { return access_ == Access::kRead; }
+  /// @returns true if the access control is write only
+  bool is_write_only() const { return access_ == Access::kWrite; }
+  /// @returns true if the access control is read/write
+  bool is_read_write() const { return access_ == Access::kReadWrite; }
 
   /// @returns the name for this type
   std::string type_name() const override;
@@ -115,6 +128,7 @@
  private:
   ImageFormat const image_format_;
   Type* const subtype_;
+  Access const access_;
 };
 
 }  // namespace ast
diff --git a/src/ast/storage_texture_test.cc b/src/ast/storage_texture_test.cc
index e2ee6e6..6098ccb 100644
--- a/src/ast/storage_texture_test.cc
+++ b/src/ast/storage_texture_test.cc
@@ -13,22 +13,8 @@
 // limitations under the License.
 
 #include "src/ast/storage_texture.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/depth_texture.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampled_texture.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
+
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
@@ -38,8 +24,9 @@
 
 TEST_F(AstStorageTextureTest, IsTexture) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  Texture* ty = create<StorageTexture>(TextureDimension::k2dArray,
-                                       ImageFormat::kRgba32Float, subtype);
+  Texture* ty =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
   EXPECT_FALSE(ty->Is<DepthTexture>());
   EXPECT_FALSE(ty->Is<SampledTexture>());
   EXPECT_TRUE(ty->Is<StorageTexture>());
@@ -47,37 +34,42 @@
 
 TEST_F(AstStorageTextureTest, Dim) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  auto* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Float, subtype);
+  auto* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
   EXPECT_EQ(s->dim(), TextureDimension::k2dArray);
 }
 
 TEST_F(AstStorageTextureTest, Format) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  auto* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Float, subtype);
+  auto* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
   EXPECT_EQ(s->image_format(), ImageFormat::kRgba32Float);
 }
 
 TEST_F(AstStorageTextureTest, TypeName) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  auto* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Float, subtype);
-  EXPECT_EQ(s->type_name(), "__storage_texture_2d_array_rgba32float");
+  auto* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
+  EXPECT_EQ(s->type_name(), "__storage_texture_2d_array_rgba32float_read");
 }
 
 TEST_F(AstStorageTextureTest, FriendlyName) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  auto* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Float, subtype);
+  auto* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
   EXPECT_EQ(s->FriendlyName(Symbols()),
-            "texture_storage_2d_array<rgba32float>");
+            "texture_storage_2d_array<rgba32float, read>");
 }
 
 TEST_F(AstStorageTextureTest, F32) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Float, *this);
-  Type* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Float, subtype);
+  Type* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Float, subtype, Access::kRead);
 
   ASSERT_TRUE(s->Is<Texture>());
   ASSERT_TRUE(s->Is<StorageTexture>());
@@ -86,8 +78,9 @@
 
 TEST_F(AstStorageTextureTest, U32) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRg32Uint, *this);
-  Type* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRg32Uint, subtype);
+  Type* s =
+      create<StorageTexture>(TextureDimension::k2dArray, ImageFormat::kRg32Uint,
+                             subtype, Access::kRead);
 
   ASSERT_TRUE(s->Is<Texture>());
   ASSERT_TRUE(s->Is<StorageTexture>());
@@ -96,8 +89,9 @@
 
 TEST_F(AstStorageTextureTest, I32) {
   auto* subtype = StorageTexture::SubtypeFor(ImageFormat::kRgba32Sint, *this);
-  Type* s = create<StorageTexture>(TextureDimension::k2dArray,
-                                   ImageFormat::kRgba32Sint, subtype);
+  Type* s =
+      create<StorageTexture>(TextureDimension::k2dArray,
+                             ImageFormat::kRgba32Sint, subtype, Access::kRead);
 
   ASSERT_TRUE(s->Is<Texture>());
   ASSERT_TRUE(s->Is<StorageTexture>());
diff --git a/src/ast/u32_test.cc b/src/ast/u32_test.cc
index af57079..e13ed85 100644
--- a/src/ast/u32_test.cc
+++ b/src/ast/u32_test.cc
@@ -14,19 +14,7 @@
 
 #include "src/ast/u32.h"
 
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
-#include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/vector.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/ast/variable.cc b/src/ast/variable.cc
index d1f3395..c473fbe 100644
--- a/src/ast/variable.cc
+++ b/src/ast/variable.cc
@@ -27,6 +27,7 @@
                    const Source& source,
                    const Symbol& sym,
                    StorageClass declared_storage_class,
+                   Access declared_access,
                    const ast::Type* type,
                    bool is_const,
                    Expression* constructor,
@@ -37,7 +38,8 @@
       is_const_(is_const),
       constructor_(constructor),
       decorations_(std::move(decorations)),
-      declared_storage_class_(declared_storage_class) {
+      declared_storage_class_(declared_storage_class),
+      declared_access_(declared_access) {
   TINT_ASSERT(symbol_.IsValid());
   TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(symbol_, program_id);
   TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(constructor, program_id);
@@ -66,8 +68,9 @@
   auto* ty = ctx->Clone(type());
   auto* ctor = ctx->Clone(constructor());
   auto decos = ctx->Clone(decorations());
-  return ctx->dst->create<Variable>(src, sym, declared_storage_class(), ty,
-                                    is_const_, ctor, decos);
+  return ctx->dst->create<Variable>(src, sym, declared_storage_class(),
+                                    declared_access(), ty, is_const_, ctor,
+                                    decos);
 }
 
 void Variable::info_to_str(const sem::Info& sem,
@@ -80,6 +83,8 @@
   out << (var_sem ? var_sem->StorageClass() : declared_storage_class())
       << std::endl;
   make_indent(out, indent);
+  out << declared_access_ << std::endl;
+  make_indent(out, indent);
   out << type_->type_name() << std::endl;
 }
 
diff --git a/src/ast/variable.h b/src/ast/variable.h
index a345fcc..a618b0b 100644
--- a/src/ast/variable.h
+++ b/src/ast/variable.h
@@ -18,6 +18,7 @@
 #include <utility>
 #include <vector>
 
+#include "src/ast/access.h"
 #include "src/ast/decoration.h"
 #include "src/ast/expression.h"
 #include "src/ast/storage_class.h"
@@ -103,6 +104,7 @@
   /// @param source the variable source
   /// @param sym the variable symbol
   /// @param declared_storage_class the declared storage class
+  /// @param declared_access the declared access control
   /// @param type the declared variable type
   /// @param is_const true if the variable is const
   /// @param constructor the constructor expression
@@ -111,6 +113,7 @@
            const Source& source,
            const Symbol& sym,
            StorageClass declared_storage_class,
+           Access declared_access,
            const ast::Type* type,
            bool is_const,
            Expression* constructor,
@@ -130,6 +133,10 @@
   StorageClass declared_storage_class() const {
     return declared_storage_class_;
   }
+
+  /// @returns the declared access control
+  Access declared_access() const { return declared_access_; }
+
   /// @returns the constructor expression or nullptr if none set
   Expression* constructor() const { return constructor_; }
   /// @returns true if the variable has an constructor
@@ -184,6 +191,7 @@
   Expression* const constructor_;
   DecorationList const decorations_;
   StorageClass const declared_storage_class_;
+  Access const declared_access_;
 };
 
 /// A list of variables
diff --git a/src/ast/variable_decl_statement_test.cc b/src/ast/variable_decl_statement_test.cc
index 37776e2..e1deb63 100644
--- a/src/ast/variable_decl_statement_test.cc
+++ b/src/ast/variable_decl_statement_test.cc
@@ -76,6 +76,7 @@
   Variable{
     a
     none
+    undefined
     __f32
   }
 }
diff --git a/src/ast/variable_test.cc b/src/ast/variable_test.cc
index 5f7ce60..fd223ac 100644
--- a/src/ast/variable_test.cc
+++ b/src/ast/variable_test.cc
@@ -92,10 +92,12 @@
 }
 
 TEST_F(VariableTest, to_str) {
-  auto* v = Var("my_var", ty.f32(), StorageClass::kFunction);
+  auto* v =
+      Var("my_var", ty.f32(), StorageClass::kFunction, ast::Access::kReadWrite);
   EXPECT_EQ(str(v), R"(Variable{
   my_var
   function
+  read_write
   __f32
 }
 )");
@@ -161,7 +163,8 @@
 }
 
 TEST_F(VariableTest, Decorated_to_str) {
-  auto* var = Var("my_var", ty.f32(), StorageClass::kFunction, Expr("expr"),
+  auto* var = Var("my_var", ty.f32(), StorageClass::kFunction,
+                  ast::Access::kRead, Expr("expr"),
                   DecorationList{
                       create<BindingDecoration>(2),
                       create<GroupDecoration>(1),
@@ -174,6 +177,7 @@
   }
   my_var
   function
+  read
   __f32
   {
     Identifier[not set]{expr}
diff --git a/src/ast/vector_test.cc b/src/ast/vector_test.cc
index f419558..4f4d0ed 100644
--- a/src/ast/vector_test.cc
+++ b/src/ast/vector_test.cc
@@ -13,19 +13,9 @@
 // limitations under the License.
 
 #include "src/ast/vector.h"
-#include "src/ast/access_control.h"
-#include "src/ast/alias.h"
-#include "src/ast/array.h"
-#include "src/ast/bool.h"
-#include "src/ast/f32.h"
+
 #include "src/ast/i32.h"
-#include "src/ast/matrix.h"
-#include "src/ast/pointer.h"
-#include "src/ast/sampler.h"
-#include "src/ast/struct.h"
 #include "src/ast/test_helper.h"
-#include "src/ast/texture.h"
-#include "src/ast/u32.h"
 
 namespace tint {
 namespace ast {
diff --git a/src/inspector/inspector.cc b/src/inspector/inspector.cc
index 51030f9..c0a100c 100644
--- a/src/inspector/inspector.cc
+++ b/src/inspector/inspector.cc
@@ -641,7 +641,7 @@
     auto* var = rsv.first;
     auto binding_info = rsv.second;
 
-    if (read_only != (var->AccessControl() == ast::AccessControl::kRead)) {
+    if (read_only != (var->Access() == ast::Access::kRead)) {
       continue;
     }
 
@@ -723,8 +723,7 @@
 
     auto* texture_type = var->Type()->UnwrapRef()->As<sem::StorageTexture>();
 
-    if (read_only !=
-        (texture_type->access_control() == ast::AccessControl::kRead)) {
+    if (read_only != (texture_type->access() == ast::Access::kRead)) {
       continue;
     }
 
diff --git a/src/inspector/inspector_test.cc b/src/inspector/inspector_test.cc
index dd3f534..00bc302 100644
--- a/src/inspector/inspector_test.cc
+++ b/src/inspector/inspector_test.cc
@@ -235,47 +235,12 @@
   /// Generates types appropriate for using in a storage buffer
   /// @param name name for the type
   /// @param member_types a vector of member types
-  /// @returns a function that returns an ast::AccessControl to the created
-  /// structure.
-  std::function<ast::AccessControl*()> MakeStorageBufferTypes(
+  /// @returns a function that returns the created structure.
+  std::function<ast::TypeName*()> MakeStorageBufferTypes(
       const std::string& name,
       std::vector<ast::Type*> member_types) {
     MakeStructType(name, member_types, true);
-    return [this, name] {
-      return ty.access(ast::AccessControl::kReadWrite, ty.type_name(name));
-    };
-  }
-
-  /// Generates types appropriate for using in a read-only storage buffer
-  /// @param name name for the type
-  /// @param member_types a vector of member types
-  /// @returns a function that returns an ast::AccessControl to the created
-  /// structure.
-  std::function<ast::AccessControl*()> MakeReadOnlyStorageBufferTypes(
-      const std::string& name,
-      std::vector<ast::Type*> member_types) {
-    MakeStructType(name, member_types, true);
-    return [this, name] {
-      return ty.access(ast::AccessControl::kRead, ty.type_name(name));
-    };
-  }
-
-  /// Adds a binding variable with a struct type to the program
-  /// @param name the name of the variable
-  /// @param type the type to use
-  /// @param storage_class the storage class to use
-  /// @param group the binding and group to use for the uniform buffer
-  /// @param binding the binding number to use for the uniform buffer
-  void AddBinding(const std::string& name,
-                  ast::Type* type,
-                  ast::StorageClass storage_class,
-                  uint32_t group,
-                  uint32_t binding) {
-    Global(name, type, storage_class, nullptr,
-           ast::DecorationList{
-               create<ast::BindingDecoration>(binding),
-               create<ast::GroupDecoration>(group),
-           });
+    return [this, name] { return ty.type_name(name); };
   }
 
   /// Adds an uniform buffer variable to the program
@@ -287,19 +252,29 @@
                         ast::Type* type,
                         uint32_t group,
                         uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kUniform, group, binding);
+    Global(name, type, ast::StorageClass::kUniform,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Adds a storage buffer variable to the program
   /// @param name the name of the variable
   /// @param type the type to use
+  /// @param access the storage buffer access control
   /// @param group the binding/group to use for the storage buffer
   /// @param binding the binding number to use for the storage buffer
   void AddStorageBuffer(const std::string& name,
                         ast::Type* type,
+                        ast::Access access,
                         uint32_t group,
                         uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kStorage, group, binding);
+    Global(name, type, ast::StorageClass::kStorage, access,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Generates a function that references a specific struct variable
@@ -341,7 +316,11 @@
   /// @param group the binding/group to use for the storage buffer
   /// @param binding the binding number to use for the storage buffer
   void AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
-    AddBinding(name, sampler_type(), ast::StorageClass::kNone, group, binding);
+    Global(name, sampler_type(),
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Adds a comparison sampler variable to the program
@@ -351,8 +330,11 @@
   void AddComparisonSampler(const std::string& name,
                             uint32_t group,
                             uint32_t binding) {
-    AddBinding(name, comparison_sampler_type(), ast::StorageClass::kNone, group,
-               binding);
+    Global(name, comparison_sampler_type(),
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Generates a SampledTexture appropriate for the params
@@ -396,7 +378,11 @@
                          ast::Type* type,
                          uint32_t group,
                          uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+    Global(name, type,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Adds a multi-sampled texture variable to the program
@@ -408,7 +394,11 @@
                               ast::Type* type,
                               uint32_t group,
                               uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+    Global(name, type,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   void AddGlobalVariable(const std::string& name, ast::Type* type) {
@@ -424,7 +414,11 @@
                        ast::Type* type,
                        uint32_t group,
                        uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+    Global(name, type,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Adds an external texture variable to the program
@@ -436,7 +430,11 @@
                           ast::Type* type,
                           uint32_t group,
                           uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+    Global(name, type,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Generates a function that references a specific sampler variable
@@ -571,15 +569,12 @@
   /// @param dim the texture dimension of the storage texture
   /// @param format the image format of the storage texture
   /// @param read_only should the access type be read only, otherwise write only
-  /// @returns the storage texture type, subtype & access control type
+  /// @returns the storage texture type
   ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim,
                                      ast::ImageFormat format,
                                      bool read_only) {
-    auto ac =
-        read_only ? ast::AccessControl::kRead : ast::AccessControl::kWrite;
-    auto* tex = ty.storage_texture(dim, format);
-
-    return ty.access(ac, tex);
+    auto access = read_only ? ast::Access::kRead : ast::Access::kWrite;
+    return ty.storage_texture(dim, format, access);
   }
 
   /// Adds a storage texture variable to the program
@@ -591,7 +586,11 @@
                          ast::Type* type,
                          uint32_t group,
                          uint32_t binding) {
-    AddBinding(name, type, ast::StorageClass::kNone, group, binding);
+    Global(name, type,
+           ast::DecorationList{
+               create<ast::BindingDecoration>(binding),
+               create<ast::GroupDecoration>(group),
+           });
   }
 
   /// Generates a function that references a storage texture variable.
@@ -1664,11 +1663,11 @@
   MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
 
   auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
-  AddStorageBuffer("sb_var", sb(), 1, 0);
+  AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
   MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
 
-  auto ro_sb = MakeReadOnlyStorageBufferTypes("rosb_type", {ty.i32()});
-  AddStorageBuffer("rosb_var", ro_sb(), 1, 1);
+  auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
+  AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
   MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
                                           {{0, ty.i32()}});
 
@@ -1949,7 +1948,7 @@
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple) {
   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -1978,7 +1977,7 @@
                                                                 ty.u32(),
                                                                 ty.f32(),
                                                             });
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction(
       "sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
@@ -2008,9 +2007,9 @@
                                                               ty.u32(),
                                                               ty.f32(),
                                                           });
-  AddStorageBuffer("sb_foo", sb_struct_type(), 0, 0);
-  AddStorageBuffer("sb_bar", sb_struct_type(), 0, 1);
-  AddStorageBuffer("sb_baz", sb_struct_type(), 2, 0);
+  AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kReadWrite, 0, 0);
+  AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kReadWrite, 0, 1);
+  AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kReadWrite, 2, 0);
 
   auto AddReferenceFunc = [this](const std::string& func_name,
                                  const std::string& var_name) {
@@ -2067,7 +2066,7 @@
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
   auto foo_struct_type =
       MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2095,7 +2094,7 @@
                                                                 ty.i32(),
                                                                 ty.array<u32>(),
                                                             });
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2120,7 +2119,7 @@
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
                                           {{0, ty.vec3<f32>()}});
@@ -2145,8 +2144,8 @@
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
-  auto foo_struct_type = MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2163,8 +2162,8 @@
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
-  auto foo_struct_type = MakeReadOnlyStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2189,14 +2188,14 @@
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
        MultipleStorageBuffers) {
-  auto sb_struct_type = MakeReadOnlyStorageBufferTypes("sb_type", {
-                                                                      ty.i32(),
-                                                                      ty.u32(),
-                                                                      ty.f32(),
-                                                                  });
-  AddStorageBuffer("sb_foo", sb_struct_type(), 0, 0);
-  AddStorageBuffer("sb_bar", sb_struct_type(), 0, 1);
-  AddStorageBuffer("sb_baz", sb_struct_type(), 2, 0);
+  auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
+                                                              ty.i32(),
+                                                              ty.u32(),
+                                                              ty.f32(),
+                                                          });
+  AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kRead, 0, 0);
+  AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kRead, 0, 1);
+  AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kRead, 2, 0);
 
   auto AddReferenceFunc = [this](const std::string& func_name,
                                  const std::string& var_name) {
@@ -2252,11 +2251,11 @@
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
   auto foo_struct_type =
-      MakeReadOnlyStorageBufferTypes("foo_type", {
-                                                     ty.i32(),
-                                                     ty.array<u32, 4>(),
-                                                 });
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+      MakeStorageBufferTypes("foo_type", {
+                                             ty.i32(),
+                                             ty.array<u32, 4>(),
+                                         });
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2281,12 +2280,11 @@
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
        ContainingRuntimeArray) {
-  auto foo_struct_type =
-      MakeReadOnlyStorageBufferTypes("foo_type", {
-                                                     ty.i32(),
-                                                     ty.array<u32>(),
-                                                 });
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+                                                                ty.i32(),
+                                                                ty.array<u32>(),
+                                                            });
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
@@ -2311,7 +2309,7 @@
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
   auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), 0, 0);
+  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
   MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
diff --git a/src/intrinsic_table.cc b/src/intrinsic_table.cc
index 4da8cbb..9cdeca7 100644
--- a/src/intrinsic_table.cc
+++ b/src/intrinsic_table.cc
@@ -286,7 +286,7 @@
 // template
 ////////////////////////////////////////////////////////////////////////////////
 using TexelFormat = ast::ImageFormat;
-using AccessControl = ast::AccessControl::Access;
+using Access = ast::Access;
 using StorageClass = ast::StorageClass;
 using ParameterUsage = sem::ParameterUsage;
 using PipelineStageSet = sem::PipelineStageSet;
@@ -577,7 +577,7 @@
   if (auto* v = ty->As<sem::StorageTexture>()) {
     if (v->dim() == dim) {
       F = Number(static_cast<uint32_t>(v->image_format()));
-      A = Number(static_cast<uint32_t>(v->access_control()));
+      A = Number(static_cast<uint32_t>(v->access()));
       return true;
     }
   }
@@ -592,7 +592,7 @@
   const sem::StorageTexture* JOIN(build_texture_storage_, suffix)(            \
       MatchState & state, Number F, Number A) {                               \
     auto format = static_cast<TexelFormat>(F.Value());                        \
-    auto access = static_cast<AccessControl>(A.Value());                      \
+    auto access = static_cast<Access>(A.Value());                             \
     auto* T = sem::StorageTexture::SubtypeFor(format, state.builder.Types()); \
     return state.builder.create<sem::StorageTexture>(dim, format, access, T); \
   }
diff --git a/src/intrinsic_table.inl b/src/intrinsic_table.inl
index 925b23b..4fca42f 100644
--- a/src/intrinsic_table.inl
+++ b/src/intrinsic_table.inl
@@ -1184,9 +1184,9 @@
 };
 
 Number ReadOrWrite::Match(MatchState&, Number number) const {
-  switch (static_cast<AccessControl>(number.Value())) {
-    case AccessControl::kRead:
-    case AccessControl::kWrite:
+  switch (static_cast<Access>(number.Value())) {
+    case Access::kRead:
+    case Access::kWrite:
       return number;
     default:
       return Number::invalid;
@@ -1212,8 +1212,8 @@
 };
 
 Number Write::Match(MatchState&, Number number) const {
-  if (number.IsAny() || number.Value() == static_cast<uint32_t>(AccessControl::kWrite)) {
-    return Number(AccessControl::kWrite);
+  if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kWrite)) {
+    return Number(Access::kWrite);
   }
   return Number::invalid;
 }
@@ -1237,8 +1237,8 @@
 };
 
 Number Read::Match(MatchState&, Number number) const {
-  if (number.IsAny() || number.Value() == static_cast<uint32_t>(AccessControl::kRead)) {
-    return Number(AccessControl::kRead);
+  if (number.IsAny() || number.Value() == static_cast<uint32_t>(Access::kRead)) {
+    return Number(Access::kRead);
   }
   return Number::invalid;
 }
diff --git a/src/intrinsic_table_test.cc b/src/intrinsic_table_test.cc
index 4fcf033..f6b9949 100644
--- a/src/intrinsic_table_test.cc
+++ b/src/intrinsic_table_test.cc
@@ -338,7 +338,7 @@
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types());
   auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d,
                                           ast::ImageFormat::kR32Float,
-                                          ast::AccessControl::kRead, subtype);
+                                          ast::Access::kRead, subtype);
 
   auto* result =
       table->Lookup(IntrinsicType::kTextureLoad, {tex, vec2_i32}, Source{});
@@ -360,7 +360,7 @@
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kR32Float, Types());
   auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d,
                                           ast::ImageFormat::kR32Float,
-                                          ast::AccessControl::kWrite, subtype);
+                                          ast::Access::kWrite, subtype);
 
   auto* result = table->Lookup(IntrinsicType::kTextureStore,
                                {tex, vec2_i32, vec4_f32}, Source{});
diff --git a/src/intrinsics.def b/src/intrinsics.def
index d63d72a..955b33f 100644
--- a/src/intrinsics.def
+++ b/src/intrinsics.def
@@ -34,7 +34,7 @@
 }
 
 // https://gpuweb.github.io/gpuweb/wgsl/#memory-access-mode
-enum access_control {
+enum access {
   read
   write
   read_write
@@ -89,10 +89,10 @@
 type texture_depth_2d_array
 type texture_depth_cube
 type texture_depth_cube_array
-type texture_storage_1d<F: texel_format, A: access_control>
-type texture_storage_2d<F: texel_format, A: access_control>
-type texture_storage_2d_array<F: texel_format, A: access_control>
-type texture_storage_3d<F: texel_format, A: access_control>
+type texture_storage_1d<F: texel_format, A: access>
+type texture_storage_2d<F: texel_format, A: access>
+type texture_storage_2d_array<F: texel_format, A: access>
+type texture_storage_3d<F: texel_format, A: access>
 type texture_external
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -245,7 +245,7 @@
 //     - Single parameter of vector type with open-number size N and element  //
 //       open-type T                                                          //
 //                                                                            //
-//   fn F<A: access_control>(texture_storage_1d<f32_texel_format, A>)         //
+//   fn F<A: access>(texture_storage_1d<f32_texel_format, A>)                 //
 //     - Single parameter of texture_storage_1d type with open-number         //
 //       access-control C, and of a texel format that is listed in            //
 //       f32_texel_format                                                     //
diff --git a/src/program_builder.h b/src/program_builder.h
index 5319a13..371ab4d 100644
--- a/src/program_builder.h
+++ b/src/program_builder.h
@@ -101,11 +101,13 @@
     ~VarOptionals();
 
     ast::StorageClass storage = ast::StorageClass::kNone;
+    ast::Access access = ast::Access::kUndefined;
     ast::Expression* constructor = nullptr;
     ast::DecorationList decorations = {};
 
    private:
     void Set(ast::StorageClass sc) { storage = sc; }
+    void Set(ast::Access ac) { access = ac; }
     void Set(ast::Expression* c) { constructor = c; }
     void Set(const ast::DecorationList& l) { decorations = l; }
 
@@ -708,29 +710,6 @@
       return builder->create<ast::Alias>(source, sym, type);
     }
 
-    /// Creates an access control qualifier type
-    /// @param access the access control
-    /// @param type the inner type
-    /// @returns the access control qualifier type
-    ast::AccessControl* access(ast::AccessControl::Access access,
-                               const ast::Type* type) const {
-      type = MaybeCreateTypename(type);
-      return type ? builder->create<ast::AccessControl>(access, type) : nullptr;
-    }
-
-    /// Creates an access control qualifier type
-    /// @param source the Source of the node
-    /// @param access the access control
-    /// @param type the inner type
-    /// @returns the access control qualifier type
-    ast::AccessControl* access(const Source& source,
-                               ast::AccessControl::Access access,
-                               const ast::Type* type) const {
-      type = MaybeCreateTypename(type);
-      return type ? builder->create<ast::AccessControl>(source, access, type)
-                  : nullptr;
-    }
-
     /// @param type the type of the pointer
     /// @param storage_class the storage class of the pointer
     /// @return the pointer to `type` with the given ast::StorageClass
@@ -823,23 +802,28 @@
 
     /// @param dims the dimensionality of the texture
     /// @param format the image format of the texture
+    /// @param access the access control of the texture
     /// @returns the storage texture
     ast::StorageTexture* storage_texture(ast::TextureDimension dims,
-                                         ast::ImageFormat format) const {
+                                         ast::ImageFormat format,
+                                         ast::Access access) const {
       auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
-      return builder->create<ast::StorageTexture>(dims, format, subtype);
+      return builder->create<ast::StorageTexture>(dims, format, subtype,
+                                                  access);
     }
 
     /// @param source the Source of the node
     /// @param dims the dimensionality of the texture
     /// @param format the image format of the texture
+    /// @param access the access control of the texture
     /// @returns the storage texture
     ast::StorageTexture* storage_texture(const Source& source,
                                          ast::TextureDimension dims,
-                                         ast::ImageFormat format) const {
+                                         ast::ImageFormat format,
+                                         ast::Access access) const {
       auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
-      return builder->create<ast::StorageTexture>(source, dims, format,
-                                                  subtype);
+      return builder->create<ast::StorageTexture>(source, dims, format, subtype,
+                                                  access);
     }
 
     /// @returns the external texture
@@ -1216,6 +1200,7 @@
   /// @param optional the optional variable settings.
   /// Can be any of the following, in any order:
   ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Access         - specifies the variable's access control
   ///   * ast::Expression*    - specifies the variable's initializer expression
   ///   * ast::DecorationList - specifies the variable's decorations
   /// Note that repeated arguments of the same type will use the last argument's
@@ -1229,7 +1214,7 @@
     type = ty.MaybeCreateTypename(type);
     VarOptionals opts(std::forward<OPTIONAL>(optional)...);
     return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage,
-                                 type, false, opts.constructor,
+                                 opts.access, type, false, opts.constructor,
                                  std::move(opts.decorations));
   }
 
@@ -1239,6 +1224,7 @@
   /// @param optional the optional variable settings.
   /// Can be any of the following, in any order:
   ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Access         - specifies the variable's access control
   ///   * ast::Expression*    - specifies the variable's initializer expression
   ///   * ast::DecorationList - specifies the variable's decorations
   /// Note that repeated arguments of the same type will use the last argument's
@@ -1252,8 +1238,8 @@
     type = ty.MaybeCreateTypename(type);
     VarOptionals opts(std::forward<OPTIONAL>(optional)...);
     return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
-                                 opts.storage, type, false, opts.constructor,
-                                 std::move(opts.decorations));
+                                 opts.storage, opts.access, type, false,
+                                 opts.constructor, std::move(opts.decorations));
   }
 
   /// @param name the variable name
@@ -1267,9 +1253,9 @@
                        ast::Expression* constructor,
                        ast::DecorationList decorations = {}) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(Sym(std::forward<NAME>(name)),
-                                 ast::StorageClass::kNone, type, true,
-                                 constructor, decorations);
+    return create<ast::Variable>(
+        Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+        ast::Access::kUndefined, type, true, constructor, decorations);
   }
 
   /// @param source the variable source
@@ -1285,9 +1271,9 @@
                        ast::Expression* constructor,
                        ast::DecorationList decorations = {}) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
-                                 ast::StorageClass::kNone, type, true,
-                                 constructor, decorations);
+    return create<ast::Variable>(
+        source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+        ast::Access::kUndefined, type, true, constructor, decorations);
   }
 
   /// @param name the parameter name
@@ -1299,9 +1285,9 @@
                        ast::Type* type,
                        ast::DecorationList decorations = {}) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(Sym(std::forward<NAME>(name)),
-                                 ast::StorageClass::kNone, type, true, nullptr,
-                                 decorations);
+    return create<ast::Variable>(
+        Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+        ast::Access::kUndefined, type, true, nullptr, decorations);
   }
 
   /// @param source the parameter source
@@ -1315,9 +1301,9 @@
                        ast::Type* type,
                        ast::DecorationList decorations = {}) {
     type = ty.MaybeCreateTypename(type);
-    return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
-                                 ast::StorageClass::kNone, type, true, nullptr,
-                                 decorations);
+    return create<ast::Variable>(
+        source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+        ast::Access::kUndefined, type, true, nullptr, decorations);
   }
 
   /// @param name the variable name
@@ -1325,6 +1311,7 @@
   /// @param optional the optional variable settings.
   /// Can be any of the following, in any order:
   ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Access         - specifies the variable's access control
   ///   * ast::Expression*    - specifies the variable's initializer expression
   ///   * ast::DecorationList - specifies the variable's decorations
   /// Note that repeated arguments of the same type will use the last argument's
@@ -1347,6 +1334,7 @@
   /// @param optional the optional variable settings.
   /// Can be any of the following, in any order:
   ///   * ast::StorageClass   - specifies the variable storage class
+  ///   * ast::Access         - specifies the variable's access control
   ///   * ast::Expression*    - specifies the variable's initializer expression
   ///   * ast::DecorationList - specifies the variable's decorations
   /// Note that repeated arguments of the same type will use the last argument's
diff --git a/src/reader/spirv/function.cc b/src/reader/spirv/function.cc
index 97d1f18..da4f579 100644
--- a/src/reader/spirv/function.cc
+++ b/src/reader/spirv/function.cc
@@ -962,7 +962,7 @@
     const auto param_name = namer_.MakeDerivedName(var_name + "_param");
     const auto param_sym = builder_.Symbols().Register(param_name);
     auto* param = create<ast::Variable>(
-        source, param_sym, ast::StorageClass::kNone,
+        source, param_sym, ast::StorageClass::kNone, ast::Access::kUndefined,
         forced_store_type->Build(builder_), true /* is const */,
         nullptr /* no constructor */, param_decos);
     decl.params.push_back(param);
@@ -2542,9 +2542,7 @@
   if (!guard_name.empty()) {
     // Declare the guard variable just before the "if", initialized to true.
     auto* guard_var =
-        create<ast::Variable>(Source{}, builder_.Symbols().Register(guard_name),
-                              ast::StorageClass::kNone, builder_.ty.bool_(),
-                              false, MakeTrue(Source{}), ast::DecorationList{});
+        builder_.Var(guard_name, builder_.ty.bool_(), MakeTrue(Source{}));
     auto* guard_decl = create<ast::VariableDeclStatement>(Source{}, guard_var);
     AddStatement(guard_decl);
   }
@@ -3102,11 +3100,9 @@
     TINT_ASSERT(def_inst);
     const auto phi_var_name = GetDefInfo(id)->phi_var;
     TINT_ASSERT(!phi_var_name.empty());
-    auto* var = create<ast::Variable>(
-        Source{}, builder_.Symbols().Register(phi_var_name),
-        ast::StorageClass::kNone,
-        parser_impl_.ConvertType(def_inst->type_id())->Build(builder_), false,
-        nullptr, ast::DecorationList{});
+    auto* var = builder_.Var(
+        phi_var_name,
+        parser_impl_.ConvertType(def_inst->type_id())->Build(builder_));
     AddStatement(create<ast::VariableDeclStatement>(Source{}, var));
   }
 
@@ -5401,7 +5397,8 @@
 
   auto* temp_var = create<ast::Variable>(
       Source{}, registered_temp_name, ast::StorageClass::kNone,
-      ast_type->Build(builder_), false, src_vector.expr, ast::DecorationList{});
+      ast::Access::kUndefined, ast_type->Build(builder_), false,
+      src_vector.expr, ast::DecorationList{});
   AddStatement(create<ast::VariableDeclStatement>(Source{}, temp_var));
 
   auto* lhs = create<ast::ArrayAccessorExpression>(
@@ -5429,7 +5426,7 @@
   // like this avoids constantly reloading the value many times.
   //
   // This technique is a combination of:
-  // - making a temporary variable and constant declaration, like  what we do
+  // - making a temporary variable and constant declaration, like what we do
   //   for VectorInsertDynamic, and
   // - building up an access-chain like access like for CompositeExtract, but
   //   on the left-hand side of the assignment.
@@ -5445,10 +5442,10 @@
   auto temp_name = namer_.MakeDerivedName(result_name);
   auto registered_temp_name = builder_.Symbols().Register(temp_name);
 
-  auto* temp_var =
-      create<ast::Variable>(Source{}, registered_temp_name,
-                            ast::StorageClass::kNone, ast_type->Build(builder_),
-                            false, src_composite.expr, ast::DecorationList{});
+  auto* temp_var = create<ast::Variable>(
+      Source{}, registered_temp_name, ast::StorageClass::kNone,
+      ast::Access::kUndefined, ast_type->Build(builder_), false,
+      src_composite.expr, ast::DecorationList{});
   AddStatement(create<ast::VariableDeclStatement>(Source{}, temp_var));
 
   TypedExpression seed_expr{ast_type, create<ast::IdentifierExpression>(
diff --git a/src/reader/spirv/function_arithmetic_test.cc b/src/reader/spirv/function_arithmetic_test.cc
index e3a0f25..4897015 100644
--- a/src/reader/spirv/function_arithmetic_test.cc
+++ b/src/reader/spirv/function_arithmetic_test.cc
@@ -159,6 +159,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       UnaryOp[not set]{
@@ -187,6 +188,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       UnaryOp[not set]{
@@ -217,6 +219,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -247,6 +250,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -279,6 +283,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       UnaryOp[not set]{
@@ -311,6 +316,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       UnaryOp[not set]{
@@ -345,6 +351,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -379,6 +386,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -415,6 +423,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       UnaryOp[not set]{
@@ -443,6 +452,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       UnaryOp[not set]{
@@ -498,6 +508,7 @@
   ss << R"(VariableConst{
     x_1
     none
+    undefined
     )"
      << GetParam().ast_type << "\n    {\n      Binary[not set]{"
      << "\n        " << GetParam().ast_lhs << "\n        " << GetParam().ast_op
@@ -543,6 +554,7 @@
   ss << R"(VariableConst{
     x_1
     none
+    undefined
     )"
      << GetParam().expected;
   auto got = ToString(p->builder(), fe.ast_body());
@@ -1021,6 +1033,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1056,6 +1069,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1166,6 +1180,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1201,6 +1216,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1253,6 +1269,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_2__f32
     {
       Binary[not set]{
@@ -1282,6 +1299,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __mat_2_2__f32
     {
       Binary[not set]{
@@ -1311,6 +1329,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_2__f32
     {
       Binary[not set]{
@@ -1340,6 +1359,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_2__f32
     {
       Binary[not set]{
@@ -1369,6 +1389,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __mat_2_2__f32
     {
       Binary[not set]{
@@ -1398,6 +1419,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_3
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -1432,6 +1454,7 @@
   EXPECT_THAT(got, HasSubstr(R"(VariableConst{
     x_3
     none
+    undefined
     __mat_3_2__f32
     {
       TypeConstructor[not set]{
@@ -1560,6 +1583,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_2
     none
+    undefined
     )" + arg.ast_type + R"(
     {
       Call[not set]{
@@ -1610,6 +1634,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __mat_2_2__f32
     {
       Call[not set]{
@@ -1648,6 +1673,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __mat_2_3__f32
     {
       Call[not set]{
@@ -1683,6 +1709,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __mat_3_2__f32
     {
       Call[not set]{
diff --git a/src/reader/spirv/function_bit_test.cc b/src/reader/spirv/function_bit_test.cc
index 4632c19..a8011cb 100644
--- a/src/reader/spirv/function_bit_test.cc
+++ b/src/reader/spirv/function_bit_test.cc
@@ -163,6 +163,7 @@
   ss << R"(VariableConst{
     x_1
     none
+    undefined
     )"
      << GetParam().ast_type << "\n    {\n      Binary[not set]{"
      << "\n        " << GetParam().ast_lhs << "\n        " << GetParam().ast_op
@@ -208,6 +209,7 @@
   ss << R"(VariableConst{
     x_1
     none
+    undefined
     )"
      << GetParam().expected;
   auto got = ToString(p->builder(), fe.ast_body());
@@ -1130,6 +1132,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       UnaryOp[not set]{
@@ -1156,6 +1159,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Bitcast[not set]<__i32>{
@@ -1184,6 +1188,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1212,6 +1217,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       UnaryOp[not set]{
@@ -1238,6 +1244,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       UnaryOp[not set]{
@@ -1268,6 +1275,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Bitcast[not set]<__vec_2__i32>{
@@ -1300,6 +1308,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1331,6 +1340,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       UnaryOp[not set]{
@@ -1386,6 +1396,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -1414,6 +1425,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1444,6 +1456,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Bitcast[not set]<__i32>{
@@ -1474,6 +1487,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Call[not set]{
@@ -1502,6 +1516,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1530,6 +1545,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1560,6 +1576,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Bitcast[not set]<__vec_2__i32>{
@@ -1590,6 +1607,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Call[not set]{
@@ -1618,6 +1636,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -1674,6 +1693,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Call[not set]{
@@ -1702,6 +1722,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1758,6 +1779,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Call[not set]{
diff --git a/src/reader/spirv/function_call_test.cc b/src/reader/spirv/function_call_test.cc
index c9ec4fc..638cb45 100644
--- a/src/reader/spirv/function_call_test.cc
+++ b/src/reader/spirv/function_call_test.cc
@@ -92,6 +92,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -148,6 +149,7 @@
   Variable{
     x_10
     none
+    undefined
     __u32
   }
 }
@@ -155,6 +157,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -218,11 +221,13 @@
     VariableConst{
       x_51
       none
+      undefined
       __u32
     }
     VariableConst{
       x_52
       none
+      undefined
       __u32
     }
   )
@@ -244,6 +249,7 @@
       VariableConst{
         x_1
         none
+        undefined
         __u32
         {
           Call[not set]{
diff --git a/src/reader/spirv/function_cfg_test.cc b/src/reader/spirv/function_cfg_test.cc
index 044e7ae..a369ac6 100644
--- a/src/reader/spirv/function_cfg_test.cc
+++ b/src/reader/spirv/function_cfg_test.cc
@@ -7910,6 +7910,7 @@
   Variable{
     guard10
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
@@ -8022,6 +8023,7 @@
   Variable{
     guard10
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
@@ -8149,6 +8151,7 @@
   Variable{
     guard10
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
diff --git a/src/reader/spirv/function_composite_test.cc b/src/reader/spirv/function_composite_test.cc
index 4fd0f07..392d021 100644
--- a/src/reader/spirv/function_composite_test.cc
+++ b/src/reader/spirv/function_composite_test.cc
@@ -92,6 +92,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -106,6 +107,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -120,6 +122,7 @@
   VariableConst{
     x_3
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -148,6 +151,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __mat_2_3__f32
     {
       TypeConstructor[not set]{
@@ -188,6 +192,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __array__u32_5
     {
       TypeConstructor[not set]{
@@ -218,6 +223,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -252,6 +258,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       MemberAccessor[not set]{
@@ -302,6 +309,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__f32
     {
       ArrayAccessor[not set]{
@@ -352,6 +360,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __f32
     {
       MemberAccessor[not set]{
@@ -385,6 +394,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       ArrayAccessor[not set]{
@@ -436,6 +446,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __i32
     {
       MemberAccessor[not set]{
@@ -478,6 +489,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       MemberAccessor[not set]{
@@ -491,6 +503,7 @@
   VariableConst{
     x_4
     none
+    undefined
     __u32
     {
       MemberAccessor[not set]{
@@ -544,6 +557,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __f32
     {
       MemberAccessor[not set]{
@@ -582,6 +596,7 @@
   Variable{
     x_1_1
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -603,6 +618,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Identifier[not set]{x_1_1}
@@ -648,6 +664,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __mat_2_3__f32
     {
       Identifier[not set]{x_1}
@@ -669,6 +686,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __mat_2_3__f32
     {
       Identifier[not set]{x_2_1}
@@ -718,6 +736,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __mat_2_3__f32
     {
       Identifier[not set]{x_1}
@@ -739,6 +758,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __mat_2_3__f32
     {
       Identifier[not set]{x_2_1}
@@ -768,6 +788,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __array__u32_5
     {
       Identifier[not set]{x_1}
@@ -785,6 +806,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __array__u32_5
     {
       Identifier[not set]{x_2_1}
@@ -835,6 +857,7 @@
   Variable{
     x_35
     none
+    undefined
     __type_name_S
   }
 }
@@ -842,6 +865,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __type_name_S
     {
       Identifier[not set]{x_35}
@@ -852,6 +876,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __type_name_S
     {
       Identifier[not set]{x_1}
@@ -869,6 +894,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __type_name_S
     {
       Identifier[not set]{x_2_1}
@@ -909,6 +935,7 @@
   Variable{
     x_40
     none
+    undefined
     __type_name_S_2
   }
 }
@@ -916,6 +943,7 @@
   Variable{
     x_41
     none
+    undefined
     __type_name_S_2
   }
 }
@@ -923,6 +951,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_40}
@@ -933,6 +962,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __type_name_S_1
     {
       Identifier[not set]{x_1}
@@ -950,6 +980,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __type_name_S_1
     {
       Identifier[not set]{x_2_1}
@@ -960,6 +991,7 @@
   VariableConst{
     x_3
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_41}
@@ -970,6 +1002,7 @@
   Variable{
     x_4_1
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_3}
@@ -987,6 +1020,7 @@
   VariableConst{
     x_4
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_4_1}
@@ -998,6 +1032,7 @@
   Variable{
     x_4_1
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_3}
@@ -1015,6 +1050,7 @@
   VariableConst{
     x_4
     none
+    undefined
     __type_name_S_2
     {
       Identifier[not set]{x_4_1}
@@ -1066,6 +1102,7 @@
   Variable{
     x_37
     none
+    undefined
     __type_name_S_1
   }
 }
@@ -1073,6 +1110,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __type_name_S_1
     {
       Identifier[not set]{x_37}
@@ -1083,6 +1121,7 @@
   Variable{
     x_2_1
     none
+    undefined
     __type_name_S_1
     {
       Identifier[not set]{x_1}
@@ -1109,6 +1148,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __type_name_S_1
     {
       Identifier[not set]{x_2_1}
@@ -1137,6 +1177,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{3u}
@@ -1147,6 +1188,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -1176,6 +1218,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __ptr_function__u32
     {
       UnaryOp[not set]{
@@ -1189,6 +1232,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __ptr_function__u32
     {
       Identifier[not set]{x_1}
@@ -1218,6 +1262,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_4__u32
     {
       TypeConstructor[not set]{
@@ -1260,6 +1305,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_4__u32
     {
       TypeConstructor[not set]{
@@ -1318,6 +1364,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -1370,6 +1417,7 @@
   EXPECT_THAT(got, HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __u32
     {
       ArrayAccessor[not set]{
@@ -1400,6 +1448,7 @@
   EXPECT_THAT(got, HasSubstr(R"(VariableConst{
     x_10
     none
+    undefined
     __u32
     {
       ArrayAccessor[not set]{
@@ -1435,6 +1484,7 @@
   Variable{
     x_10_1
     none
+    undefined
     __vec_2__u32
     {
       Identifier[not set]{x_1}
@@ -1452,6 +1502,7 @@
   VariableConst{
     x_10
     none
+    undefined
     __vec_2__u32
     {
       Identifier[not set]{x_10_1}
diff --git a/src/reader/spirv/function_conversion_test.cc b/src/reader/spirv/function_conversion_test.cc
index 6d77b27..cb3d381 100644
--- a/src/reader/spirv/function_conversion_test.cc
+++ b/src/reader/spirv/function_conversion_test.cc
@@ -86,6 +86,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -111,6 +112,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Bitcast[not set]<__vec_2__f32>{
@@ -239,6 +241,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       TypeConstructor[not set]{
@@ -265,6 +268,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       TypeConstructor[not set]{
@@ -293,6 +297,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -319,6 +324,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -382,6 +388,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       TypeConstructor[not set]{
@@ -410,6 +417,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       TypeConstructor[not set]{
@@ -436,6 +444,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -464,6 +473,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -526,6 +536,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       TypeConstructor[not set]{
@@ -552,6 +563,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -580,6 +592,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -606,6 +619,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -686,6 +700,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       TypeConstructor[not set]{
@@ -728,6 +743,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -778,6 +794,7 @@
   EXPECT_THAT(ToString(p->builder(), fe.ast_body()), HasSubstr(R"(VariableConst{
         x_82
         none
+        undefined
         __u32
         {
           TypeConstructor[not set]{
diff --git a/src/reader/spirv/function_decl_test.cc b/src/reader/spirv/function_decl_test.cc
index cb38e8f..41cc2f0 100644
--- a/src/reader/spirv/function_decl_test.cc
+++ b/src/reader/spirv/function_decl_test.cc
@@ -118,16 +118,19 @@
     VariableConst{
       a
       none
+      undefined
       __u32
     }
     VariableConst{
       b
       none
+      undefined
       __f32
     }
     VariableConst{
       c
       none
+      undefined
       __i32
     }
   )
@@ -162,16 +165,19 @@
     VariableConst{
       x_14
       none
+      undefined
       __u32
     }
     VariableConst{
       x_15
       none
+      undefined
       __f32
     }
     VariableConst{
       x_16
       none
+      undefined
       __i32
     }
   )
diff --git a/src/reader/spirv/function_glsl_std_450_test.cc b/src/reader/spirv/function_glsl_std_450_test.cc
index bb5756c..3e5b5e4 100644
--- a/src/reader/spirv/function_glsl_std_450_test.cc
+++ b/src/reader/spirv/function_glsl_std_450_test.cc
@@ -188,6 +188,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -219,6 +220,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -250,6 +252,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -282,6 +285,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -314,6 +318,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -345,6 +350,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -376,6 +382,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -408,6 +415,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -440,6 +448,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -474,6 +483,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -507,6 +517,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -540,6 +551,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -572,6 +584,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -605,6 +618,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -638,6 +652,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_3__f32
     {
       Call[not set]{
@@ -744,6 +759,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Call[not set]{
@@ -776,6 +792,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Call[not set]{
@@ -808,6 +825,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Call[not set]{
@@ -841,6 +859,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Call[not set]{
@@ -874,6 +893,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Call[not set]{
@@ -908,6 +928,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__i32
     {
       Call[not set]{
@@ -954,6 +975,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -987,6 +1009,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1019,6 +1042,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -1053,6 +1077,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1099,6 +1124,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{1.000000}
@@ -1123,6 +1149,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__f32
     {
       Call[not set]{
@@ -1152,6 +1179,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_3__f32
     {
       Call[not set]{
@@ -1181,6 +1209,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_4__f32
     {
       Call[not set]{
@@ -1213,6 +1242,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1232,6 +1262,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1265,6 +1296,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1287,6 +1319,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1323,6 +1356,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1345,6 +1379,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1381,6 +1416,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Bitcast[not set]<__u32>{
@@ -1404,6 +1440,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__u32
     {
       Bitcast[not set]<__vec_2__u32>{
@@ -1441,6 +1478,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Bitcast[not set]<__i32>{
@@ -1463,6 +1501,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__i32
     {
       Bitcast[not set]<__vec_2__i32>{
@@ -1499,6 +1538,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Bitcast[not set]<__i32>{
@@ -1521,6 +1561,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__i32
     {
       Bitcast[not set]<__vec_2__i32>{
@@ -1557,6 +1598,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __i32
     {
       Bitcast[not set]<__i32>{
@@ -1580,6 +1622,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __vec_2__i32
     {
       Bitcast[not set]<__vec_2__i32>{
@@ -1633,6 +1676,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -1677,6 +1721,7 @@
   VariableConst{
     x_1
     none
+    undefined
     )" + std::string(param.vec_size == 2 ? "__vec_2__f32" : "__vec_4__f32") +
                               R"(
     {
diff --git a/src/reader/spirv/function_logical_test.cc b/src/reader/spirv/function_logical_test.cc
index e1f3f44..180e115 100644
--- a/src/reader/spirv/function_logical_test.cc
+++ b/src/reader/spirv/function_logical_test.cc
@@ -210,6 +210,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -236,6 +237,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -290,6 +292,7 @@
   ss << R"(VariableConst{
     x_1
     none
+    undefined
     )"
      << GetParam().ast_type << "\n    {\n      Binary[not set]{"
      << "\n        " << GetParam().ast_lhs << "\n        " << GetParam().ast_op
@@ -728,6 +731,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -758,6 +762,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -796,6 +801,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -826,6 +832,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -864,6 +871,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -894,6 +902,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -932,6 +941,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -962,6 +972,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -1000,6 +1011,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -1030,6 +1042,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -1068,6 +1081,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -1098,6 +1112,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       UnaryOp[not set]{
@@ -1139,6 +1154,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       Call[not set]{
@@ -1171,6 +1187,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
@@ -1203,6 +1220,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __f32
     {
       Call[not set]{
@@ -1238,6 +1256,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1284,6 +1303,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__u32
     {
       Call[not set]{
@@ -1328,6 +1348,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       Call[not set]{
@@ -1362,6 +1383,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       Call[not set]{
@@ -1396,6 +1418,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       Call[not set]{
@@ -1426,6 +1449,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       Call[not set]{
@@ -1460,6 +1484,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __bool
     {
       Call[not set]{
@@ -1490,6 +1515,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __vec_2__bool
     {
       Call[not set]{
diff --git a/src/reader/spirv/function_memory_test.cc b/src/reader/spirv/function_memory_test.cc
index f44846a..0ef8989 100644
--- a/src/reader/spirv/function_memory_test.cc
+++ b/src/reader/spirv/function_memory_test.cc
@@ -180,6 +180,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_1}
@@ -210,6 +211,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -220,6 +222,7 @@
   VariableConst{
     x_3
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -252,6 +255,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -873,7 +877,8 @@
     }
     myvar
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   })"));
 }
 
@@ -1017,6 +1022,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __ptr_storage__u32
     {
       UnaryOp[not set]{
@@ -1078,6 +1084,7 @@
   Variable{
     x_2
     none
+    undefined
     __ptr_storage__u32
   }
 }
@@ -1176,6 +1183,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       Call[not set]{
diff --git a/src/reader/spirv/function_misc_test.cc b/src/reader/spirv/function_misc_test.cc
index c22e4d1..4ecea55 100644
--- a/src/reader/spirv/function_misc_test.cc
+++ b/src/reader/spirv/function_misc_test.cc
@@ -78,6 +78,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -88,6 +89,7 @@
   VariableConst{
     x_12
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{0u}
@@ -98,6 +100,7 @@
   VariableConst{
     x_13
     none
+    undefined
     __i32
     {
       ScalarConstructor[not set]{0}
@@ -108,6 +111,7 @@
   VariableConst{
     x_14
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{0.000000}
@@ -142,6 +146,7 @@
   VariableConst{
     x_14
     none
+    undefined
     __vec_2__bool
     {
       TypeConstructor[not set]{
@@ -156,6 +161,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -170,6 +176,7 @@
   VariableConst{
     x_12
     none
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -184,6 +191,7 @@
   VariableConst{
     x_13
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -221,6 +229,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -231,6 +240,7 @@
   VariableConst{
     x_12
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{0u}
@@ -241,6 +251,7 @@
   VariableConst{
     x_13
     none
+    undefined
     __i32
     {
       ScalarConstructor[not set]{0}
@@ -251,6 +262,7 @@
   VariableConst{
     x_14
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{0.000000}
@@ -282,6 +294,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -296,6 +309,7 @@
   VariableConst{
     x_12
     none
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -310,6 +324,7 @@
   VariableConst{
     x_13
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -343,6 +358,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __mat_2_2__f32
     {
       TypeConstructor[not set]{
@@ -385,6 +401,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -418,6 +435,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -541,6 +559,7 @@
       VariableConst{
         x_81
         none
+        undefined
         __f32
         {
           Binary[not set]{
diff --git a/src/reader/spirv/function_var_test.cc b/src/reader/spirv/function_var_test.cc
index dc474a0..c2ba7ec 100644
--- a/src/reader/spirv/function_var_test.cc
+++ b/src/reader/spirv/function_var_test.cc
@@ -108,6 +108,7 @@
   Variable{
     x_1
     none
+    undefined
     __u32
   }
 }
@@ -115,6 +116,7 @@
   Variable{
     x_2
     none
+    undefined
     __u32
   }
 }
@@ -122,6 +124,7 @@
   Variable{
     x_3
     none
+    undefined
     __u32
   }
 }
@@ -147,6 +150,7 @@
   Variable{
     a
     none
+    undefined
     __u32
   }
 }
@@ -154,6 +158,7 @@
   Variable{
     b
     none
+    undefined
     __u32
   }
 }
@@ -161,6 +166,7 @@
   Variable{
     c
     none
+    undefined
     __u32
   }
 }
@@ -186,6 +192,7 @@
   Variable{
     a
     none
+    undefined
     __u32
   }
 }
@@ -193,6 +200,7 @@
   Variable{
     b
     none
+    undefined
     __i32
   }
 }
@@ -200,6 +208,7 @@
   Variable{
     c
     none
+    undefined
     __f32
   }
 }
@@ -227,6 +236,7 @@
   Variable{
     a
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
@@ -237,6 +247,7 @@
   Variable{
     b
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -247,6 +258,7 @@
   Variable{
     c
     none
+    undefined
     __i32
     {
       ScalarConstructor[not set]{-1}
@@ -257,6 +269,7 @@
   Variable{
     d
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{1u}
@@ -267,6 +280,7 @@
   Variable{
     e
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{1.500000}
@@ -301,6 +315,7 @@
   Variable{
     a
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -311,6 +326,7 @@
   Variable{
     b
     none
+    undefined
     __i32
     {
       ScalarConstructor[not set]{0}
@@ -321,6 +337,7 @@
   Variable{
     c
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{0u}
@@ -331,6 +348,7 @@
   Variable{
     d
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{0.000000}
@@ -361,6 +379,7 @@
   Variable{
     x_200
     none
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -400,6 +419,7 @@
   Variable{
     x_200
     none
+    undefined
     __mat_2_3__f32
     {
       TypeConstructor[not set]{
@@ -447,6 +467,7 @@
   Variable{
     x_200
     none
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -486,6 +507,7 @@
   Variable{
     x_200
     none
+    undefined
     __type_name_Arr
     {
       TypeConstructor[not set]{
@@ -521,6 +543,7 @@
   Variable{
     x_200
     none
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -561,6 +584,7 @@
   Variable{
     x_200
     none
+    undefined
     __type_name_Arr
     {
       TypeConstructor[not set]{
@@ -596,6 +620,7 @@
   Variable{
     x_200
     none
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -636,6 +661,7 @@
   Variable{
     x_200
     none
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -682,6 +708,7 @@
   Variable{
     x_25
     none
+    undefined
     __u32
   }
 }
@@ -730,6 +757,7 @@
   Variable{
     x_25
     none
+    undefined
     __u32
   }
 }
@@ -737,6 +765,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Binary[not set]{
@@ -802,6 +831,7 @@
   Variable{
     x_25
     none
+    undefined
     __u32
   }
 }
@@ -809,6 +839,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Binary[not set]{
@@ -906,6 +937,7 @@
     Variable{
       x_2
       none
+      undefined
       __u32
     }
   }
@@ -1019,6 +1051,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{1u}
@@ -1036,6 +1069,7 @@
   VariableConst{
     x_3
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -1109,6 +1143,7 @@
       VariableConst{
         x_1
         none
+        undefined
         __u32
         {
           ScalarConstructor[not set]{1u}
@@ -1126,6 +1161,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -1196,6 +1232,7 @@
       VariableConst{
         x_1
         none
+        undefined
         __u32
         {
           ScalarConstructor[not set]{1u}
@@ -1215,6 +1252,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -1274,6 +1312,7 @@
   VariableConst{
     x_1
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{1u}
@@ -1284,6 +1323,7 @@
   VariableConst{
     x_2
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_1}
@@ -1352,6 +1392,7 @@
     Variable{
       x_2_phi
       none
+      undefined
       __u32
     }
   }
@@ -1359,6 +1400,7 @@
     Variable{
       x_3_phi
       none
+      undefined
       __u32
     }
   }
@@ -1366,6 +1408,7 @@
     VariableConst{
       x_101
       none
+      undefined
       __bool
       {
         Identifier[not set]{x_7}
@@ -1376,6 +1419,7 @@
     VariableConst{
       x_102
       none
+      undefined
       __bool
       {
         Identifier[not set]{x_8}
@@ -1403,6 +1447,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_2_phi}
@@ -1413,6 +1458,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_3_phi}
@@ -1499,6 +1545,7 @@
     Variable{
       x_2_phi
       none
+      undefined
       __u32
     }
   }
@@ -1506,6 +1553,7 @@
     Variable{
       x_3_phi
       none
+      undefined
       __u32
     }
   }
@@ -1513,6 +1561,7 @@
     VariableConst{
       x_101
       none
+      undefined
       __bool
       {
         Identifier[not set]{x_7}
@@ -1523,6 +1572,7 @@
     VariableConst{
       x_102
       none
+      undefined
       __bool
       {
         Identifier[not set]{x_8}
@@ -1550,6 +1600,7 @@
       Variable{
         x_4
         none
+        undefined
         __u32
       }
     }
@@ -1557,6 +1608,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_2_phi}
@@ -1567,6 +1619,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_3_phi}
@@ -1660,6 +1713,7 @@
   VariableConst{
     x_101
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_17}
@@ -1671,6 +1725,7 @@
     Variable{
       x_2_phi
       none
+      undefined
       __u32
     }
   }
@@ -1678,6 +1733,7 @@
     Variable{
       x_5_phi
       none
+      undefined
       __u32
     }
   }
@@ -1694,6 +1750,7 @@
       Variable{
         x_7
         none
+        undefined
         __u32
       }
     }
@@ -1701,6 +1758,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_2_phi}
@@ -1711,6 +1769,7 @@
       VariableConst{
         x_5
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_5_phi}
@@ -1721,6 +1780,7 @@
       VariableConst{
         x_4
         none
+        undefined
         __u32
         {
           Binary[not set]{
@@ -1735,6 +1795,7 @@
       VariableConst{
         x_6
         none
+        undefined
         __u32
         {
           Binary[not set]{
@@ -1832,6 +1893,7 @@
   VariableConst{
     x_101
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_7}
@@ -1842,6 +1904,7 @@
   VariableConst{
     x_102
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_8}
@@ -1853,6 +1916,7 @@
     Variable{
       x_2_phi
       none
+      undefined
       __u32
     }
   }
@@ -1890,6 +1954,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_2_phi}
@@ -1958,6 +2023,7 @@
   VariableConst{
     x_101
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_7}
@@ -1968,6 +2034,7 @@
   VariableConst{
     x_102
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_8}
@@ -1979,6 +2046,7 @@
     Variable{
       x_2_phi
       none
+      undefined
       __u32
     }
   }
@@ -2017,6 +2085,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_2_phi}
@@ -2084,6 +2153,7 @@
   Variable{
     x_35_phi
     none
+    undefined
     __u32
   }
 }
@@ -2124,6 +2194,7 @@
   VariableConst{
     x_35
     none
+    undefined
     __u32
     {
       Identifier[not set]{x_35_phi}
@@ -2174,6 +2245,7 @@
   Variable{
     x_101_phi
     none
+    undefined
     __bool
   }
 }
@@ -2181,6 +2253,7 @@
   VariableConst{
     x_11
     none
+    undefined
     __bool
     {
       Binary[not set]{
@@ -2195,6 +2268,7 @@
   VariableConst{
     x_12
     none
+    undefined
     __bool
     {
       UnaryOp[not set]{
@@ -2223,6 +2297,7 @@
   VariableConst{
     x_101
     none
+    undefined
     __bool
     {
       Identifier[not set]{x_101_phi}
@@ -2291,6 +2366,7 @@
       Variable{
         x_81_phi_1
         none
+        undefined
         __f32
       }
     }
@@ -2298,6 +2374,7 @@
       VariableConst{
         x_81
         none
+        undefined
         __f32
         {
           Identifier[not set]{x_81_phi_1}
diff --git a/src/reader/spirv/parser_impl.cc b/src/reader/spirv/parser_impl.cc
index a573634..9f6a865 100644
--- a/src/reader/spirv/parser_impl.cc
+++ b/src/reader/spirv/parser_impl.cc
@@ -1354,6 +1354,7 @@
     return nullptr;
   }
 
+  ast::Access access = ast::Access::kUndefined;
   if (sc == ast::StorageClass::kStorage) {
     bool read_only = false;
     if (auto* tn = storage_type->As<Named>()) {
@@ -1361,9 +1362,7 @@
     }
 
     // Apply the access(read) or access(read_write) modifier.
-    auto access =
-        read_only ? ast::AccessControl::kRead : ast::AccessControl::kReadWrite;
-    storage_type = ty_.AccessControl(storage_type, access);
+    access = read_only ? ast::Access::kRead : ast::Access::kReadWrite;
   }
 
   // Handle variables (textures and samplers) are always in the handle
@@ -1387,7 +1386,7 @@
   // `var` declarations will have a resolved type of ref<storage>, but at the
   // AST level both `var` and `let` are declared with the same type.
   return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
-                               storage_type->Build(builder_), is_const,
+                               access, storage_type->Build(builder_), is_const,
                                constructor, decorations);
 }
 
@@ -1501,7 +1500,7 @@
   }
 
   auto source = GetSourceForInst(inst);
-  auto* ast_type = original_ast_type->UnwrapAliasAndAccess();
+  auto* ast_type = original_ast_type->UnwrapAlias();
 
   // TODO(dneto): Note: NullConstant for int, uint, float map to a regular 0.
   // So canonicalization should map that way too.
@@ -1577,7 +1576,7 @@
   }
 
   auto* original_type = type;
-  type = type->UnwrapAliasAndAccess();
+  type = type->UnwrapAlias();
 
   if (type->Is<Bool>()) {
     return create<ast::ScalarConstructorExpression>(
@@ -2123,15 +2122,13 @@
         ast_store_type = ty_.SampledTexture(dim, ast_sampled_component_type);
       }
     } else {
-      const auto access = usage.IsStorageReadTexture()
-                              ? ast::AccessControl::kRead
-                              : ast::AccessControl::kWrite;
+      const auto access = usage.IsStorageReadTexture() ? ast::Access::kRead
+                                                       : ast::Access::kWrite;
       const auto format = enum_converter_.ToImageFormat(image_type->format());
       if (format == ast::ImageFormat::kNone) {
         return nullptr;
       }
-      ast_store_type =
-          ty_.AccessControl(ty_.StorageTexture(dim, format), access);
+      ast_store_type = ty_.StorageTexture(dim, format, access);
     }
   } else {
     Fail() << "unsupported: UniformConstant variable is not a recognized "
diff --git a/src/reader/spirv/parser_impl_function_decl_test.cc b/src/reader/spirv/parser_impl_function_decl_test.cc
index 5b2e753..a78ce0a 100644
--- a/src/reader/spirv/parser_impl_function_decl_test.cc
+++ b/src/reader/spirv/parser_impl_function_decl_test.cc
@@ -220,6 +220,7 @@
       VariableConst{
         leaf_result
         none
+        undefined
         __u32
         {
           Call[not set]{
@@ -243,6 +244,7 @@
       VariableConst{
         branch_result
         none
+        undefined
         __u32
         {
           Call[not set]{
@@ -307,16 +309,19 @@
     VariableConst{
       a
       none
+      undefined
       __u32
     }
     VariableConst{
       b
       none
+      undefined
       __f32
     }
     VariableConst{
       c
       none
+      undefined
       __i32
     }
   )
@@ -347,16 +352,19 @@
     VariableConst{
       x_14
       none
+      undefined
       __u32
     }
     VariableConst{
       x_15
       none
+      undefined
       __f32
     }
     VariableConst{
       x_16
       none
+      undefined
       __i32
     }
   )
diff --git a/src/reader/spirv/parser_impl_handle_test.cc b/src/reader/spirv/parser_impl_handle_test.cc
index 8569bb5..116b7bc 100644
--- a/src/reader/spirv/parser_impl_handle_test.cc
+++ b/src/reader/spirv/parser_impl_handle_test.cc
@@ -1270,6 +1270,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   })"}));
 
@@ -1288,6 +1289,7 @@
     }
     x_10
     none
+    undefined
     __sampled_texture_1d__f32
   })"},
                              DeclUnderspecifiedHandleCase{R"(
@@ -1304,7 +1306,8 @@
     }
     x_10
     none
-    __access_control_read_only__storage_texture_1d_rg32float
+    undefined
+    __storage_texture_1d_rg32float_read
   })"},
                              DeclUnderspecifiedHandleCase{R"(
          OpDecorate %10 NonReadable
@@ -1320,7 +1323,8 @@
     }
     x_10
     none
-    __access_control_write_only__storage_texture_1d_rg32float
+    undefined
+    __storage_texture_1d_rg32float_write
   })"}));
 
 // Test handle declaration or error, when there is an image access.
@@ -1453,6 +1457,7 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   }
 )"},
@@ -1639,6 +1644,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1648,6 +1654,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -1672,6 +1679,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1681,6 +1689,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -1716,6 +1725,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1725,6 +1735,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
             R"(
@@ -1755,6 +1766,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1764,6 +1776,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
             R"(
@@ -1803,6 +1816,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1812,6 +1826,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -1837,6 +1852,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1846,6 +1862,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -1882,6 +1899,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1891,6 +1909,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -1923,6 +1942,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1932,6 +1952,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -1965,6 +1986,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -1974,6 +1996,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -2026,6 +2049,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2035,6 +2059,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   }
   Variable{
@@ -2044,6 +2069,7 @@
     }
     x_30
     none
+    undefined
     __sampler_comparison
   })",
                         R"(
@@ -2051,6 +2077,7 @@
       VariableConst{
         x_200
         none
+        undefined
         __vec_4__f32
         {
           TypeConstructor[not set]{
@@ -2074,6 +2101,7 @@
       VariableConst{
         x_210
         none
+        undefined
         __f32
         {
           Call[not set]{
@@ -2105,6 +2133,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2114,6 +2143,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
                         R"(
@@ -2138,6 +2168,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2147,6 +2178,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
                         R"(
@@ -2182,6 +2214,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2191,6 +2224,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
             R"(
@@ -2221,6 +2255,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2230,6 +2265,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
             R"(
@@ -2276,6 +2312,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2285,6 +2322,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
                         R"(
@@ -2309,6 +2347,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2318,6 +2357,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
                         R"(
@@ -2353,6 +2393,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2362,6 +2403,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
                         R"(
@@ -2392,6 +2434,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2401,6 +2444,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
                         R"(
@@ -2440,6 +2484,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2449,6 +2494,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube
   })",
                         R"(
@@ -2473,6 +2519,7 @@
     }
     x_10
     none
+    undefined
     __sampler_comparison
   }
   Variable{
@@ -2482,6 +2529,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube_array
   })",
                         R"(
@@ -2522,6 +2570,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2531,6 +2580,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2556,6 +2606,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2565,6 +2616,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -2601,6 +2653,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2610,6 +2663,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2642,6 +2696,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2651,6 +2706,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2685,6 +2741,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2694,6 +2751,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -2739,6 +2797,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2748,6 +2807,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2774,6 +2834,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2783,6 +2844,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -2820,6 +2882,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2829,6 +2892,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2861,6 +2925,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2870,6 +2935,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                         R"(
@@ -2905,6 +2971,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2914,6 +2981,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -2957,6 +3025,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -2966,6 +3035,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
                         R"(
@@ -3020,6 +3090,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -3029,6 +3100,7 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(
@@ -3053,6 +3125,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -3062,6 +3135,7 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
          R"(
@@ -3165,7 +3239,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_write
   })",
                               R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3195,7 +3270,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32float
+    undefined
+    __storage_texture_2d_r32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3221,7 +3297,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32float
+    undefined
+    __storage_texture_2d_r32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3246,7 +3323,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32float
+    undefined
+    __storage_texture_2d_r32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3270,7 +3348,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32float
+    undefined
+    __storage_texture_2d_r32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3290,7 +3369,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rg32float
+    undefined
+    __storage_texture_2d_rg32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3315,7 +3395,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rg32float
+    undefined
+    __storage_texture_2d_rg32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3339,7 +3420,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rg32float
+    undefined
+    __storage_texture_2d_rg32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3360,7 +3442,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3456,7 +3539,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32uint
+    undefined
+    __storage_texture_2d_rgba32uint_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3476,7 +3560,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32sint
+    undefined
+    __storage_texture_2d_rgba32sint_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3506,7 +3591,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_write
   })"},
         // Sampled type is float, texel is unsigned int
         {"%int 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vu1234",
@@ -3521,7 +3607,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_write
   })"},
         // Sampled type is unsigned int, texel is float
         {"%uint 2D 0 0 0 2 Rgba32ui", "OpImageWrite %im %vi12 %vf1234",
@@ -3536,7 +3623,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32uint
+    undefined
+    __storage_texture_2d_rgba32uint_write
   })"},
         // Sampled type is signed int, texel is float
         {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vf1234",
@@ -3551,7 +3639,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32sint
+    undefined
+    __storage_texture_2d_rgba32sint_write
   })"}}));
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3573,7 +3662,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32uint
+    undefined
+    __storage_texture_2d_rgba32uint_write
   })"},
         // Sampled type is signed int, texel is unsigned int
         {"%int 2D 0 0 0 2 Rgba32i", "OpImageWrite %im %vi12 %vu1234",
@@ -3588,7 +3678,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_rgba32sint
+    undefined
+    __storage_texture_2d_rgba32sint_write
   })"}}));
 
 INSTANTIATE_TEST_SUITE_P(
@@ -3607,7 +3698,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32uint
+    undefined
+    __storage_texture_2d_r32uint_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3632,7 +3724,8 @@
     }
     x_20
     none
-    __access_control_write_only__storage_texture_2d_r32sint
+    undefined
+    __storage_texture_2d_r32sint_write
   })",
          R"(Call[not set]{
       Identifier[not set]{textureStore}
@@ -3661,12 +3754,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_read
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3694,12 +3789,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3723,12 +3820,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3752,12 +3851,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           TypeConstructor[not set]{
@@ -3787,12 +3888,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           TypeConstructor[not set]{
@@ -3830,12 +3933,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           TypeConstructor[not set]{
@@ -3876,12 +3981,14 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3909,12 +4016,14 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3959,12 +4068,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -3987,12 +4098,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__u32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__u32
         {
           Call[not set]{
@@ -4020,12 +4133,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__i32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__i32
         {
           Call[not set]{
@@ -4057,12 +4172,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -4084,12 +4201,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_rgba32uint
+    undefined
+    __storage_texture_2d_rgba32uint_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__u32
         {
           Call[not set]{
@@ -4117,12 +4236,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_rgba32sint
+    undefined
+    __storage_texture_2d_rgba32sint_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__i32
         {
           Call[not set]{
@@ -4158,6 +4279,7 @@
     }
     x_10
     none
+    undefined
     __sampler_sampler
   }
   Variable{
@@ -4167,12 +4289,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_4__f32
         {
           Call[not set]{
@@ -4206,12 +4330,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_1d_rgba32float
+    undefined
+    __storage_texture_1d_rgba32float_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -4238,12 +4364,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_rgba32float
+    undefined
+    __storage_texture_2d_rgba32float_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4270,12 +4398,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_3d_rgba32float
+    undefined
+    __storage_texture_3d_rgba32float_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4300,12 +4430,14 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4341,12 +4473,14 @@
     }
     x_20
     none
-    __access_control_read_only__storage_texture_2d_array_rgba32float
+    undefined
+    __storage_texture_2d_array_rgba32float_read
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4388,12 +4522,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_1d__f32
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -4420,12 +4556,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4452,12 +4590,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_3d__f32
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4484,12 +4624,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_cube__f32
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4519,12 +4661,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4551,12 +4695,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_2__i32
         {
           TypeConstructor[not set]{
@@ -4596,12 +4742,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4640,12 +4788,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_cube_array__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4681,12 +4831,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4723,12 +4875,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube_array
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __vec_3__i32
         {
           TypeConstructor[not set]{
@@ -4771,12 +4925,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_1d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -4814,12 +4970,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_1d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __u32
         {
           TypeConstructor[not set]{
@@ -4854,12 +5012,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -4881,12 +5041,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d_array__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -4908,12 +5070,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_3d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -4935,12 +5099,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_cube__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -4962,12 +5128,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_cube_array__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -4989,12 +5157,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -5016,12 +5186,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_2d_array
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -5043,12 +5215,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -5070,12 +5244,14 @@
     }
     x_20
     none
+    undefined
     __depth_texture_cube_array
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -5102,12 +5278,14 @@
     }
     x_20
     none
+    undefined
     __sampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __u32
         {
           TypeConstructor[not set]{
@@ -5136,12 +5314,14 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   })",
                               R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __i32
         {
           Call[not set]{
@@ -5172,12 +5352,14 @@
     }
     x_20
     none
+    undefined
     __multisampled_texture_2d__f32
   })",
          R"(VariableDeclStatement{
       VariableConst{
         x_99
         none
+        undefined
         __u32
         {
           TypeConstructor[not set]{
@@ -6231,6 +6413,7 @@
   Variable{
     var_1
     none
+    undefined
     __vec_4__f32
   }
 }
@@ -6238,6 +6421,7 @@
   VariableConst{
     x_22
     none
+    undefined
     __vec_4__f32
     {
       Call[not set]{
@@ -6259,6 +6443,7 @@
   VariableConst{
     x_26
     none
+    undefined
     __vec_4__f32
     {
       Call[not set]{
diff --git a/src/reader/spirv/parser_impl_module_var_test.cc b/src/reader/spirv/parser_impl_module_var_test.cc
index 7899896..6109957 100644
--- a/src/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/reader/spirv/parser_impl_module_var_test.cc
@@ -196,6 +196,7 @@
   Variable{
     x_52
     workgroup
+    undefined
     __f32
   })"));
 }
@@ -217,6 +218,7 @@
   Variable{
     the_counter
     workgroup
+    undefined
     __f32
   })"));
 }
@@ -238,6 +240,7 @@
   Variable{
     my_own_private_idaho
     private
+    undefined
     __f32
   })"));
 }
@@ -267,6 +270,7 @@
     }
     x_52
     in
+    undefined
     __u32
   })"));
 }
@@ -322,6 +326,7 @@
     }
     gl_Position
     out
+    undefined
     __vec_4__f32
   })"))
       << module_str;
@@ -547,6 +552,7 @@
     }
     gl_Position
     out
+    undefined
     __vec_4__f32
   }
   Function main -> __void
@@ -601,6 +607,7 @@
   Variable{
     x_900
     private
+    undefined
     __f32
   }
   Variable{
@@ -609,6 +616,7 @@
     }
     gl_Position
     out
+    undefined
     __vec_4__f32
   }
   Function main -> __void
@@ -672,6 +680,7 @@
     }
     gl_Position
     out
+    undefined
     __vec_4__f32
   }
   Function main -> __void
@@ -770,6 +779,7 @@
   Variable{
     x_900
     private
+    undefined
     __f32
   }
   Function main -> __void
@@ -961,6 +971,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_1
     private
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
@@ -969,6 +980,7 @@
   Variable{
     x_2
     private
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -977,6 +989,7 @@
   Variable{
     x_3
     private
+    undefined
     __i32
     {
       ScalarConstructor[not set]{-1}
@@ -985,6 +998,7 @@
   Variable{
     x_4
     private
+    undefined
     __u32
     {
       ScalarConstructor[not set]{1u}
@@ -993,6 +1007,7 @@
   Variable{
     x_5
     private
+    undefined
     __f32
     {
       ScalarConstructor[not set]{1.500000}
@@ -1018,6 +1033,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_1
     private
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -1026,6 +1042,7 @@
   Variable{
     x_2
     private
+    undefined
     __i32
     {
       ScalarConstructor[not set]{0}
@@ -1034,6 +1051,7 @@
   Variable{
     x_3
     private
+    undefined
     __u32
     {
       ScalarConstructor[not set]{0u}
@@ -1042,6 +1060,7 @@
   Variable{
     x_4
     private
+    undefined
     __f32
     {
       ScalarConstructor[not set]{0.000000}
@@ -1067,6 +1086,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_1
     private
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -1075,6 +1095,7 @@
   Variable{
     x_2
     private
+    undefined
     __i32
     {
       ScalarConstructor[not set]{0}
@@ -1083,6 +1104,7 @@
   Variable{
     x_3
     private
+    undefined
     __u32
     {
       ScalarConstructor[not set]{0u}
@@ -1091,6 +1113,7 @@
   Variable{
     x_4
     private
+    undefined
     __f32
     {
       ScalarConstructor[not set]{0.000000}
@@ -1114,6 +1137,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -1137,6 +1161,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__bool
     {
       TypeConstructor[not set]{
@@ -1160,6 +1185,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__bool
     {
       TypeConstructor[not set]{
@@ -1186,6 +1212,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -1209,6 +1236,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__u32
     {
       TypeConstructor[not set]{
@@ -1235,6 +1263,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -1258,6 +1287,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__i32
     {
       TypeConstructor[not set]{
@@ -1284,6 +1314,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -1307,6 +1338,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __vec_2__f32
     {
       TypeConstructor[not set]{
@@ -1339,6 +1371,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __mat_2_3__f32
     {
       TypeConstructor[not set]{
@@ -1375,6 +1408,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __mat_2_3__f32
     {
       TypeConstructor[not set]{
@@ -1411,6 +1445,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __mat_2_3__f32
     {
       TypeConstructor[not set]{
@@ -1451,6 +1486,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -1474,6 +1510,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -1497,6 +1534,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __array__u32_2
     {
       TypeConstructor[not set]{
@@ -1525,6 +1563,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -1554,6 +1593,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -1585,6 +1625,7 @@
   EXPECT_THAT(module_str, HasSubstr(R"(Variable{
     x_200
     private
+    undefined
     __type_name_S
     {
       TypeConstructor[not set]{
@@ -1623,6 +1664,7 @@
     }
     myvar
     in
+    undefined
     __u32
   })"))
       << module_str;
@@ -1674,7 +1716,8 @@
     }
     x_1
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   })"))
       << module_str;
 }
@@ -1727,7 +1770,8 @@
     }
     x_1
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   })"))
       << module_str;
 }
@@ -1784,7 +1828,8 @@
   Variable{
     x_1
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   }
 )")) << module_str;
 }
@@ -1817,7 +1862,8 @@
   Variable{
     myvar
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   }
 })")) << module_str;
 }
@@ -1849,7 +1895,8 @@
   Variable{
     myvar
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   }
 })")) << module_str;
 }
@@ -1905,7 +1952,8 @@
   Variable{
     x_1
     storage
-    __access_control_read_only__type_name_S
+    read
+    __type_name_S
   }
 })")) << module_str;
 }
@@ -1937,7 +1985,8 @@
   Variable{
     x_1
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   }
 })")) << module_str;
 }
@@ -1972,7 +2021,8 @@
   Variable{
     x_1
     storage
-    __access_control_read_write__type_name_S
+    read_write
+    __type_name_S
   }
 })")) << module_str;
 }
@@ -1996,6 +2046,7 @@
     }
     myconst
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{true}
@@ -2023,6 +2074,7 @@
     }
     myconst
     none
+    undefined
     __bool
     {
       ScalarConstructor[not set]{false}
@@ -2050,6 +2102,7 @@
     }
     myconst
     none
+    undefined
     __u32
     {
       ScalarConstructor[not set]{42u}
@@ -2077,6 +2130,7 @@
     }
     myconst
     none
+    undefined
     __i32
     {
       ScalarConstructor[not set]{42}
@@ -2104,6 +2158,7 @@
     }
     myconst
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{2.500000}
@@ -2129,6 +2184,7 @@
   VariableConst{
     myconst
     none
+    undefined
     __f32
     {
       ScalarConstructor[not set]{2.500000}
@@ -2212,6 +2268,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2221,6 +2278,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2254,6 +2312,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2263,6 +2322,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2296,6 +2356,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2305,6 +2366,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2363,6 +2425,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2372,6 +2435,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -2402,6 +2466,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2411,6 +2476,7 @@
       VariableConst{
         x_11
         none
+        undefined
         __ptr_in__u32
         {
           UnaryOp[not set]{
@@ -2424,6 +2490,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           UnaryOp[not set]{
@@ -2457,6 +2524,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2466,6 +2534,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -2574,6 +2643,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2583,6 +2653,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -2616,6 +2687,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2625,6 +2697,7 @@
       VariableConst{
         x_4
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -2658,6 +2731,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2667,6 +2741,7 @@
       VariableConst{
         x_4
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -2699,6 +2774,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2708,6 +2784,7 @@
       VariableConst{
         x_3
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2744,6 +2821,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2753,6 +2831,7 @@
       VariableConst{
         x_4
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2789,6 +2868,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -2798,6 +2878,7 @@
       VariableConst{
         x_4
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -2852,6 +2933,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -2888,6 +2970,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -2924,6 +3007,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -2959,6 +3043,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -3001,6 +3086,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -3043,6 +3129,7 @@
     }
     x_1
     out
+    undefined
     __u32
   })"));
 
@@ -3100,6 +3187,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3109,6 +3197,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3142,6 +3231,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3151,6 +3241,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3184,6 +3275,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3193,6 +3285,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3251,6 +3344,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3260,6 +3354,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -3290,6 +3385,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3299,6 +3395,7 @@
       VariableConst{
         x_11
         none
+        undefined
         __ptr_in__u32
         {
           UnaryOp[not set]{
@@ -3312,6 +3409,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           UnaryOp[not set]{
@@ -3345,6 +3443,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3354,6 +3453,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -3427,6 +3527,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3436,6 +3537,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3469,6 +3571,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3478,6 +3581,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3511,6 +3615,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3520,6 +3625,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __i32
         {
           TypeConstructor[not set]{
@@ -3576,6 +3682,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3585,6 +3692,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -3615,6 +3723,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3624,6 +3733,7 @@
       VariableConst{
         x_11
         none
+        undefined
         __ptr_in__u32
         {
           UnaryOp[not set]{
@@ -3637,6 +3747,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           UnaryOp[not set]{
@@ -3670,6 +3781,7 @@
     }
     x_1
     in
+    undefined
     __u32
   })"));
 
@@ -3679,6 +3791,7 @@
       VariableConst{
         x_2
         none
+        undefined
         __u32
         {
           Identifier[not set]{x_1}
@@ -3832,6 +3945,7 @@
       R"(Variable{
     x_1
     private
+    undefined
     __u32
   }
 )";
@@ -3856,6 +3970,7 @@
       R"(Variable{
     x_1
     private
+    undefined
     __u32
   }
 )";
@@ -3903,21 +4018,25 @@
   Variable{
     x_1
     private
+    undefined
     __u32
   }
   Variable{
     x_2
     private
+    undefined
     __u32
   }
   Variable{
     x_3
     private
+    undefined
     __u32
   }
   Variable{
     x_4
     private
+    undefined
     __u32
   }
   Function main_1 -> __void
@@ -3934,6 +4053,7 @@
       }
       x_1_param
       none
+      undefined
       __u32
     }
     VariableConst{
@@ -3942,6 +4062,7 @@
       }
       x_3_param
       none
+      undefined
       __u32
     }
   )
diff --git a/src/reader/spirv/parser_type.cc b/src/reader/spirv/parser_type.cc
index a2db682..4f46b7d 100644
--- a/src/reader/spirv/parser_type.cc
+++ b/src/reader/spirv/parser_type.cc
@@ -33,7 +33,6 @@
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Vector);
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Matrix);
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Array);
-TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::AccessControl);
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Sampler);
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::Texture);
 TINT_INSTANTIATE_TYPEINFO(tint::reader::spirv::DepthTexture);
@@ -79,12 +78,6 @@
   }
 };
 
-struct AccessControlHasher {
-  size_t operator()(const AccessControl& t) const {
-    return utils::Hash(t.type, t.access);
-  }
-};
-
 struct MultisampledTextureHasher {
   size_t operator()(const MultisampledTexture& t) const {
     return utils::Hash(t.dims, t.type);
@@ -99,7 +92,7 @@
 
 struct StorageTextureHasher {
   size_t operator()(const StorageTexture& t) const {
-    return utils::Hash(t.dims, t.format);
+    return utils::Hash(t.dims, t.format, t.access);
   }
 };
 }  // namespace
@@ -124,10 +117,6 @@
   return a.type == b.type && a.size == b.size && a.stride == b.stride;
 }
 
-static bool operator==(const AccessControl& a, const AccessControl& b) {
-  return a.type == b.type && a.access == b.access;
-}
-
 static bool operator==(const MultisampledTexture& a,
                        const MultisampledTexture& b) {
   return a.dims == b.dims && a.type == b.type;
@@ -200,14 +189,6 @@
   return b.ty.array(type->Build(b), size, stride);
 }
 
-AccessControl::AccessControl(const Type* t, ast::AccessControl::Access a)
-    : type(t), access(a) {}
-AccessControl::AccessControl(const AccessControl&) = default;
-
-ast::Type* AccessControl::Build(ProgramBuilder& b) const {
-  return b.ty.access(access, type->Build(b));
-}
-
 Sampler::Sampler(ast::SamplerKind k) : kind(k) {}
 Sampler::Sampler(const Sampler&) = default;
 
@@ -241,12 +222,14 @@
   return b.ty.sampled_texture(dims, type->Build(b));
 }
 
-StorageTexture::StorageTexture(ast::TextureDimension d, ast::ImageFormat f)
-    : Base(d), format(f) {}
+StorageTexture::StorageTexture(ast::TextureDimension d,
+                               ast::ImageFormat f,
+                               ast::Access a)
+    : Base(d), format(f), access(a) {}
 StorageTexture::StorageTexture(const StorageTexture&) = default;
 
 ast::Type* StorageTexture::Build(ProgramBuilder& b) const {
-  return b.ty.storage_texture(dims, format);
+  return b.ty.storage_texture(dims, format, access);
 }
 
 Named::Named(Symbol n) : name(n) {}
@@ -296,11 +279,6 @@
       matrices_;
   /// Map of Array to the returned Array type instance
   std::unordered_map<spirv::Array, const spirv::Array*, ArrayHasher> arrays_;
-  /// Map of AccessControl to the returned AccessControl type instance
-  std::unordered_map<spirv::AccessControl,
-                     const spirv::AccessControl*,
-                     AccessControlHasher>
-      access_controls_;
   /// Map of type name to returned Alias instance
   std::unordered_map<Symbol, const spirv::Alias*> aliases_;
   /// Map of type name to returned Struct instance
@@ -352,27 +330,11 @@
   return type;
 }
 
-const Type* Type::UnwrapAliasAndAccess() const {
-  auto* type = this;
-  while (true) {
-    if (auto* alias = type->As<Alias>()) {
-      type = alias->type;
-    } else if (auto* access = type->As<AccessControl>()) {
-      type = access->type;
-    } else {
-      break;
-    }
-  }
-  return type;
-}
-
 const Type* Type::UnwrapAll() const {
   auto* type = this;
   while (true) {
     if (auto* alias = type->As<Alias>()) {
       type = alias->type;
-    } else if (auto* access = type->As<AccessControl>()) {
-      type = access->type;
     } else if (auto* ptr = type->As<Pointer>()) {
       type = ptr->type;
     } else {
@@ -500,14 +462,6 @@
       [&] { return state->allocator_.Create<spirv::Array>(el, size, stride); });
 }
 
-const spirv::AccessControl* TypeManager::AccessControl(
-    const Type* ty,
-    ast::AccessControl::Access ac) {
-  return utils::GetOrCreate(
-      state->access_controls_, spirv::AccessControl(ty, ac),
-      [&] { return state->allocator_.Create<spirv::AccessControl>(ty, ac); });
-}
-
 const spirv::Alias* TypeManager::Alias(Symbol name, const Type* ty) {
   return utils::GetOrCreate(state->aliases_, name, [&] {
     return state->allocator_.Create<spirv::Alias>(name, ty);
@@ -553,10 +507,12 @@
 
 const spirv::StorageTexture* TypeManager::StorageTexture(
     ast::TextureDimension dims,
-    ast::ImageFormat fmt) {
+    ast::ImageFormat fmt,
+    ast::Access access) {
   return utils::GetOrCreate(
-      state->storage_textures_, spirv::StorageTexture(dims, fmt), [&] {
-        return state->allocator_.Create<spirv::StorageTexture>(dims, fmt);
+      state->storage_textures_, spirv::StorageTexture(dims, fmt, access), [&] {
+        return state->allocator_.Create<spirv::StorageTexture>(dims, fmt,
+                                                               access);
       });
 }
 
@@ -614,12 +570,6 @@
   return ss.str();
 }
 
-std::string AccessControl::String() const {
-  std::stringstream ss;
-  ss << "[[access(" << access << ")]] " << type->String();
-  return ss.str();
-}
-
 std::string Sampler::String() const {
   switch (kind) {
     case ast::SamplerKind::kSampler:
@@ -650,7 +600,7 @@
 
 std::string StorageTexture::String() const {
   std::stringstream ss;
-  ss << "texture_storage_" << dims << "<" << format << ">";
+  ss << "texture_storage_" << dims << "<" << format << ", " << access << ">";
   return ss.str();
 }
 
diff --git a/src/reader/spirv/parser_type.h b/src/reader/spirv/parser_type.h
index c01c4e1..85d80cd 100644
--- a/src/reader/spirv/parser_type.h
+++ b/src/reader/spirv/parser_type.h
@@ -19,7 +19,7 @@
 #include <string>
 #include <vector>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/sampler.h"
 #include "src/ast/storage_class.h"
 #include "src/ast/storage_texture.h"
@@ -56,9 +56,6 @@
   /// @returns the inner most aliased type if this is an alias, `this` otherwise
   const Type* UnwrapAlias() const;
 
-  /// @returns the type with all aliasing and access control removed
-  const Type* UnwrapAliasAndAccess() const;
-
   /// @returns the type with all aliasing, access control and pointers removed
   const Type* UnwrapAll() const;
 
@@ -290,33 +287,6 @@
   uint32_t const stride;
 };
 
-/// `[[access]]` type
-struct AccessControl : public Castable<AccessControl, Type> {
-  /// Constructor
-  /// @param ty the inner type
-  /// @param ac the access control
-  AccessControl(const Type* ty, ast::AccessControl::Access ac);
-
-  /// Copy constructor
-  /// @param other the other type to copy
-  AccessControl(const AccessControl& other);
-
-  /// @return the
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  ast::Type* Build(ProgramBuilder& b) const override;
-
-#ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
-#endif  // NDEBUG
-
-  /// the inner type
-  Type const* const type;
-  /// the access control
-  ast::AccessControl::Access const access;
-};
-
 /// `sampler` type
 struct Sampler : public Castable<Sampler, Type> {
   /// Constructor
@@ -427,7 +397,8 @@
   /// Constructor
   /// @param d the texture dimensions
   /// @param f the storage image format
-  StorageTexture(ast::TextureDimension d, ast::ImageFormat f);
+  /// @param a the access control
+  StorageTexture(ast::TextureDimension d, ast::ImageFormat f, ast::Access a);
 
   /// Copy constructor
   /// @param other the other type to copy
@@ -444,6 +415,9 @@
 
   /// the storage image format
   ast::ImageFormat const format;
+
+  /// the access control
+  ast::Access const access;
 };
 
 /// Base class for named types
@@ -556,12 +530,6 @@
   /// @return a Array type. Repeated calls with the same arguments will return
   /// the same pointer.
   const spirv::Array* Array(const Type* el, uint32_t sz, uint32_t st);
-  /// @param ty the inner type
-  /// @param ac the access control
-  /// @return a AccessControl type. Repeated calls with the same arguments will
-  /// return the same pointer.
-  const spirv::AccessControl* AccessControl(const Type* ty,
-                                            ast::AccessControl::Access ac);
   /// @param n the alias name
   /// @param t the aliased type
   /// @return a Alias type. Repeated calls with the same arguments will return
@@ -594,10 +562,12 @@
                                               const Type* t);
   /// @param d the texture dimensions
   /// @param f the storage image format
+  /// @param a the access control
   /// @return a StorageTexture type. Repeated calls with the same arguments will
   /// return the same pointer.
   const spirv::StorageTexture* StorageTexture(ast::TextureDimension d,
-                                              ast::ImageFormat f);
+                                              ast::ImageFormat f,
+                                              ast::Access a);
 
  private:
   struct State;
diff --git a/src/reader/spirv/parser_type_test.cc b/src/reader/spirv/parser_type_test.cc
index fa89aa3..8818e3f 100644
--- a/src/reader/spirv/parser_type_test.cc
+++ b/src/reader/spirv/parser_type_test.cc
@@ -35,8 +35,6 @@
   EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
   EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
   EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
-  EXPECT_EQ(ty.AccessControl(ty.I32(), ast::AccessControl::kRead),
-            ty.AccessControl(ty.I32(), ast::AccessControl::kRead));
   EXPECT_EQ(ty.Alias(sym, ty.I32()), ty.Alias(sym, ty.I32()));
   EXPECT_EQ(ty.Struct(sym, {ty.I32()}), ty.Struct(sym, {ty.I32()}));
   EXPECT_EQ(ty.Sampler(ast::SamplerKind::kSampler),
@@ -47,10 +45,10 @@
             ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()));
   EXPECT_EQ(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
             ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()));
-  EXPECT_EQ(
-      ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
-      ty.StorageTexture(ast::TextureDimension::k2d,
-                        ast::ImageFormat::kR16Sint));
+  EXPECT_EQ(ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead),
+            ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead));
 }
 
 TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
@@ -70,10 +68,6 @@
   EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.U32(), 3, 2));
   EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 2, 2));
   EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 3));
-  EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::kRead),
-            ty.AccessControl(ty.U32(), ast::AccessControl::kRead));
-  EXPECT_NE(ty.AccessControl(ty.I32(), ast::AccessControl::kRead),
-            ty.AccessControl(ty.I32(), ast::AccessControl::kWrite));
   EXPECT_NE(ty.Alias(sym_a, ty.I32()), ty.Alias(sym_b, ty.I32()));
   EXPECT_NE(ty.Struct(sym_a, {ty.I32()}), ty.Struct(sym_b, {ty.I32()}));
   EXPECT_NE(ty.Sampler(ast::SamplerKind::kSampler),
@@ -88,14 +82,18 @@
             ty.SampledTexture(ast::TextureDimension::k3d, ty.I32()));
   EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
             ty.SampledTexture(ast::TextureDimension::k2d, ty.U32()));
-  EXPECT_NE(
-      ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
-      ty.StorageTexture(ast::TextureDimension::k3d,
-                        ast::ImageFormat::kR16Sint));
-  EXPECT_NE(
-      ty.StorageTexture(ast::TextureDimension::k2d, ast::ImageFormat::kR16Sint),
-      ty.StorageTexture(ast::TextureDimension::k2d,
-                        ast::ImageFormat::kR32Sint));
+  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead),
+            ty.StorageTexture(ast::TextureDimension::k3d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead));
+  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead),
+            ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR32Sint, ast::Access::kRead));
+  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kRead),
+            ty.StorageTexture(ast::TextureDimension::k2d,
+                              ast::ImageFormat::kR16Sint, ast::Access::kWrite));
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl.cc b/src/reader/wgsl/parser_impl.cc
index 67bd0a3..a45fe37 100644
--- a/src/reader/wgsl/parser_impl.cc
+++ b/src/reader/wgsl/parser_impl.cc
@@ -66,9 +66,9 @@
 const char kFragmentStage[] = "fragment";
 const char kComputeStage[] = "compute";
 
-const char kReadAccessControl[] = "read";
-const char kWriteAccessControl[] = "write";
-const char kReadWriteAccessControl[] = "read_write";
+const char kReadAccess[] = "read";
+const char kWriteAccess[] = "write";
+const char kReadWriteAccess[] = "read_write";
 
 ast::Builtin ident_to_builtin(const std::string& str) {
   if (str == "position") {
@@ -204,9 +204,13 @@
 ParserImpl::TypedIdentifier::TypedIdentifier(const TypedIdentifier&) = default;
 
 ParserImpl::TypedIdentifier::TypedIdentifier(ast::Type* type_in,
+                                             ast::Access access_in,
                                              std::string name_in,
                                              Source source_in)
-    : type(type_in), name(std::move(name_in)), source(std::move(source_in)) {}
+    : type(type_in),
+      access(access_in),
+      name(std::move(name_in)),
+      source(std::move(source_in)) {}
 
 ParserImpl::TypedIdentifier::~TypedIdentifier() = default;
 
@@ -237,10 +241,12 @@
 ParserImpl::VarDeclInfo::VarDeclInfo(Source source_in,
                                      std::string name_in,
                                      ast::StorageClass storage_class_in,
+                                     ast::Access access_in,
                                      ast::Type* type_in)
     : source(std::move(source_in)),
       name(std::move(name_in)),
       storage_class(storage_class_in),
+      access(access_in),
       type(type_in) {}
 
 ParserImpl::VarDeclInfo::~VarDeclInfo() = default;
@@ -477,7 +483,8 @@
   return create<ast::Variable>(
       decl->source,                             // source
       builder_.Symbols().Register(decl->name),  // symbol
-      decl->storage_class,                      // storage_class
+      decl->storage_class,                      // storage class
+      decl->access,                             // access control
       decl->type,                               // type
       false,                                    // is_const
       constructor,                              // constructor
@@ -511,7 +518,8 @@
   return create<ast::Variable>(
       decl->source,                             // source
       builder_.Symbols().Register(decl->name),  // symbol
-      ast::StorageClass::kNone,                 // storage_class
+      ast::StorageClass::kNone,                 // storage class
+      ast::Access::kUndefined,                  // access control
       decl->type,                               // type
       true,                                     // is_const
       initializer,                              // constructor
@@ -519,26 +527,27 @@
 }
 
 // variable_decl
-//   : VAR variable_storage_decoration? variable_ident_decl
+//   : VAR variable_qualifier? variable_ident_decl
 Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl(bool allow_inferred) {
-  if (!match(Token::Type::kVar))
+  Source source;
+  if (!match(Token::Type::kVar, &source))
     return Failure::kNoMatch;
 
-  ast::StorageClass sc = ast::StorageClass::kNone;
-  auto explicit_sc = variable_storage_decoration();
-  if (explicit_sc.errored)
+  VariableQualifier vq;
+  auto explicit_vq = variable_qualifier();
+  if (explicit_vq.errored)
     return Failure::kErrored;
-  if (explicit_sc.matched) {
-    sc = explicit_sc.value;
+  if (explicit_vq.matched) {
+    vq = explicit_vq.value;
 
     // TODO(crbug.com/tint/697): Remove this.
-    if (sc == ast::StorageClass::kInput) {
-      deprecated(explicit_sc.source,
+    if (vq.storage_class == ast::StorageClass::kInput) {
+      deprecated(explicit_vq.source,
                  "use an entry point parameter instead of a variable in the "
                  "`in` storage class");
     }
-    if (sc == ast::StorageClass::kOutput) {
-      deprecated(explicit_sc.source,
+    if (vq.storage_class == ast::StorageClass::kOutput) {
+      deprecated(explicit_vq.source,
                  "use an entry point return value instead of a variable in the "
                  "`out` storage class");
     }
@@ -549,7 +558,20 @@
   if (decl.errored)
     return Failure::kErrored;
 
-  return VarDeclInfo{decl->source, decl->name, sc, decl->type};
+  auto access = vq.access;
+
+  if (access == ast::Access::kUndefined &&
+      decl->access != ast::Access::kUndefined) {
+    // TODO(crbug.com/tint/846): Remove this
+    access = decl->access;
+    std::stringstream msg;
+    msg << "declare access with var<" << vq.storage_class << ", " << access
+        << "> instead of using [[access]] decoration";
+    deprecated(source, msg.str());
+  }
+
+  return VarDeclInfo{decl->source, decl->name, vq.storage_class, access,
+                     decl->type};
 }
 
 // texture_sampler_types
@@ -559,7 +581,8 @@
 //  | multisampled_texture_type LESS_THAN type_decl GREATER_THAN
 //  | storage_texture_type LESS_THAN image_storage_type
 //                         COMMA access GREATER_THAN
-Maybe<ast::Type*> ParserImpl::texture_sampler_types() {
+Maybe<ast::Type*> ParserImpl::texture_sampler_types(
+    ast::DecorationList& decos) {
   auto type = sampler_type();
   if (type.matched)
     return type;
@@ -601,7 +624,7 @@
   if (storage.matched) {
     const char* use = "storage texture type";
     using StorageTextureInfo =
-        std::pair<tint::ast::ImageFormat, tint::ast::AccessControl::Access>;
+        std::pair<tint::ast::ImageFormat, tint::ast::Access>;
     auto params = expect_lt_gt_block(use, [&]() -> Expect<StorageTextureInfo> {
       auto format = expect_image_storage_type(use);
       if (format.errored) {
@@ -609,14 +632,23 @@
       }
 
       if (!match(Token::Type::kComma)) {
+        // TODO(crbug.com/tint/846): Remove this, along with the decos parameter
+        auto access_decos = take_decorations<ast::AccessDecoration>(decos);
+        if (access_decos.size() > 1) {
+          return add_error(access_decos[1]->source(),
+                           "multiple access decorations not allowed");
+        }
+        if (access_decos.size() == 0) {
+          return add_error(source_range, "expected access control");
+        }
+
         deprecated(
             peek().source(),
             "access control is expected as last parameter of storage textures");
-        return std::make_pair(format.value,
-                              tint::ast::AccessControl::kReadWrite);
+        return std::make_pair(format.value, access_decos[0]->value());
       }
 
-      auto access = expect_access_type();
+      auto access = expect_access("access control");
       if (access.errored) {
         return Failure::kErrored;
       }
@@ -628,19 +660,8 @@
       return Failure::kErrored;
     }
 
-    ast::Type* ty =
-        builder_.ty.storage_texture(source_range, storage.value, params->first);
-
-    if (params->second != tint::ast::AccessControl::kReadWrite) {
-      // TODO(crbug.com/tint/846): The ast::AccessControl decoration is
-      // deprecated, but while we're migrating existing WGSL over to the new
-      // style of having the access part of the storage texture, we need to
-      // support both old and new styles. For now, have the new syntax emulate
-      // the old style AST.
-      ty = builder_.ty.access(params->second, ty);
-    }
-
-    return ty;
+    return builder_.ty.storage_texture(source_range, storage.value,
+                                       params->first, params->second);
   }
 
   return Failure::kNoMatch;
@@ -906,7 +927,8 @@
     return Failure::kErrored;
 
   if (allow_inferred && !peek().Is(Token::Type::kColon)) {
-    return TypedIdentifier{nullptr, ident.value, ident.source};
+    return TypedIdentifier{nullptr, ast::Access::kUndefined, ident.value,
+                           ident.source};
   }
 
   if (!expect(use, Token::Type::kColon))
@@ -916,8 +938,6 @@
   if (decos.errored)
     return Failure::kErrored;
 
-  auto access_decos = take_decorations<ast::AccessDecoration>(decos.value);
-
   auto t = peek();
   auto type = type_decl(decos.value);
   if (type.errored)
@@ -925,52 +945,65 @@
   if (!type.matched)
     return add_error(t.source(), "invalid type", use);
 
+  auto access_decos = take_decorations<ast::AccessDecoration>(decos.value);
+
   if (!expect_decorations_consumed(decos.value))
     return Failure::kErrored;
 
   if (access_decos.size() > 1)
     return add_error(ident.source, "multiple access decorations not allowed");
 
-  ast::Type* ty = type.value;
+  auto access =
+      access_decos.empty() ? ast::Access::kUndefined : access_decos[0]->value();
 
-  for (auto* deco : access_decos) {
-    // If we have an access control decoration then we take it and wrap our
-    // type up with that decoration
-    ty = builder_.ty.access(deco->source(),
-                            deco->As<ast::AccessDecoration>()->value(), ty);
-  }
-  return TypedIdentifier{ty, ident.value, ident.source};
+  return TypedIdentifier{type.value, access, ident.value, ident.source};
 }
 
-Expect<ast::AccessControl::Access> ParserImpl::expect_access_type() {
-  auto ident = expect_ident("access_type");
+Expect<ast::Access> ParserImpl::expect_access(const std::string& use) {
+  auto ident = expect_ident(use);
   if (ident.errored)
     return Failure::kErrored;
 
-  if (ident.value == kReadAccessControl)
-    return {ast::AccessControl::kRead, ident.source};
-  if (ident.value == kWriteAccessControl)
-    return {ast::AccessControl::kWrite, ident.source};
-  if (ident.value == kReadWriteAccessControl)
-    return {ast::AccessControl::kReadWrite, ident.source};
+  if (ident.value == kReadAccess)
+    return {ast::Access::kRead, ident.source};
+  if (ident.value == kWriteAccess)
+    return {ast::Access::kWrite, ident.source};
+  if (ident.value == kReadWriteAccess)
+    return {ast::Access::kReadWrite, ident.source};
 
   return add_error(ident.source, "invalid value for access decoration");
 }
 
-// variable_storage_decoration
-//   : LESS_THAN storage_class GREATER_THAN
-Maybe<ast::StorageClass> ParserImpl::variable_storage_decoration() {
-  if (!peek().IsLessThan())
+// variable_qualifier
+//   : LESS_THAN storage_class (COMMA access_mode)? GREATER_THAN
+Maybe<ParserImpl::VariableQualifier> ParserImpl::variable_qualifier() {
+  if (!peek().IsLessThan()) {
     return Failure::kNoMatch;
+  }
 
-  const char* use = "variable decoration";
+  auto* use = "variable declaration";
+  auto vq = expect_lt_gt_block(use, [&]() -> Expect<VariableQualifier> {
+    auto source = make_source_range();
+    auto sc = expect_storage_class(use);
+    if (sc.errored) {
+      return Failure::kErrored;
+    }
+    if (match(Token::Type::kComma)) {
+      auto ac = expect_access(use);
+      if (ac.errored) {
+        return Failure::kErrored;
+      }
+      return VariableQualifier{sc.value, ac.value};
+    }
+    return Expect<VariableQualifier>{
+        VariableQualifier{sc.value, ast::Access::kUndefined}, source};
+  });
 
-  auto sc = expect_lt_gt_block(use, [&] { return expect_storage_class(use); });
-
-  if (sc.errored)
+  if (vq.errored) {
     return Failure::kErrored;
+  }
 
-  return sc;
+  return vq;
 }
 
 // type_alias
@@ -1088,7 +1121,7 @@
     return expect_type_decl_matrix(t);
   }
 
-  auto texture_or_sampler = texture_sampler_types();
+  auto texture_or_sampler = texture_sampler_types(decos);
   if (texture_or_sampler.errored)
     return Failure::kErrored;
   if (texture_or_sampler.matched)
@@ -1449,7 +1482,8 @@
   auto* var =
       create<ast::Variable>(decl->source,                             // source
                             builder_.Symbols().Register(decl->name),  // symbol
-                            ast::StorageClass::kNone,  // storage_class
+                            ast::StorageClass::kNone,  // storage class
+                            ast::Access::kUndefined,   // access control
                             decl->type,                // type
                             true,                      // is_const
                             nullptr,                   // constructor
@@ -1712,7 +1746,8 @@
     auto* var = create<ast::Variable>(
         decl->source,                             // source
         builder_.Symbols().Register(decl->name),  // symbol
-        ast::StorageClass::kNone,                 // storage_class
+        ast::StorageClass::kNone,                 // storage class
+        ast::Access::kUndefined,                  // access control
         decl->type,                               // type
         true,                                     // is_const
         constructor.value,                        // constructor
@@ -1741,7 +1776,8 @@
   auto* var =
       create<ast::Variable>(decl->source,                             // source
                             builder_.Symbols().Register(decl->name),  // symbol
-                            decl->storage_class,     // storage_class
+                            decl->storage_class,     // storage class
+                            decl->access,            // access control
                             decl->type,              // type
                             false,                   // is_const
                             constructor,             // constructor
@@ -2947,7 +2983,7 @@
   if (s == kAccessDecoration) {
     const char* use = "access decoration";
     return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_access_type();
+      auto val = expect_access("access control");
       if (val.errored)
         return Failure::kErrored;
 
diff --git a/src/reader/wgsl/parser_impl.h b/src/reader/wgsl/parser_impl.h
index 5a58359..afbcce1 100644
--- a/src/reader/wgsl/parser_impl.h
+++ b/src/reader/wgsl/parser_impl.h
@@ -22,7 +22,7 @@
 #include <utility>
 #include <vector>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/program_builder.h"
 #include "src/reader/wgsl/parser_impl_detail.h"
 #include "src/reader/wgsl/token.h"
@@ -208,14 +208,20 @@
     TypedIdentifier(const TypedIdentifier& other);
     /// Constructor
     /// @param type_in parsed type
+    /// @param access_in parsed access
     /// @param name_in parsed identifier
     /// @param source_in source to the identifier
-    TypedIdentifier(ast::Type* type_in, std::string name_in, Source source_in);
+    TypedIdentifier(ast::Type* type_in,
+                    ast::Access access_in,
+                    std::string name_in,
+                    Source source_in);
     /// Destructor
     ~TypedIdentifier();
 
     /// Parsed type. May be nullptr for inferred types.
     ast::Type* type = nullptr;
+    /// The access control. TODO(crbug.com/tint/846): Remove
+    ast::Access access = ast::Access::kUndefined;
     /// Parsed identifier.
     std::string name;
     /// Source to the identifier.
@@ -270,10 +276,12 @@
     /// @param source_in variable declaration source
     /// @param name_in variable name
     /// @param storage_class_in variable storage class
+    /// @param access_in variable access control
     /// @param type_in variable type
     VarDeclInfo(Source source_in,
                 std::string name_in,
                 ast::StorageClass storage_class_in,
+                ast::Access access_in,
                 ast::Type* type_in);
     /// Destructor
     ~VarDeclInfo();
@@ -283,11 +291,21 @@
     /// Variable name
     std::string name;
     /// Variable storage class
-    ast::StorageClass storage_class;
+    ast::StorageClass storage_class = ast::StorageClass::kNone;
+    /// Variable access control
+    ast::Access access = ast::Access::kUndefined;
     /// Variable type
     ast::Type* type = nullptr;
   };
 
+  /// VariableQualifier contains the parsed information for a variable qualifier
+  struct VariableQualifier {
+    /// The variable's storage class
+    ast::StorageClass storage_class = ast::StorageClass::kNone;
+    /// The variable's access control
+    ast::Access access = ast::Access::kUndefined;
+  };
+
   /// Creates a new parser using the given file
   /// @param file the input source file to parse
   explicit ParserImpl(Source::File const* file);
@@ -400,9 +418,9 @@
   Expect<TypedIdentifier> expect_variable_ident_decl(
       const std::string& use,
       bool allow_inferred = false);
-  /// Parses a `variable_storage_decoration` grammar element
-  /// @returns the storage class or StorageClass::kNone if none matched
-  Maybe<ast::StorageClass> variable_storage_decoration();
+  /// Parses a `variable_qualifier` grammar element
+  /// @returns the variable qualifier information
+  Maybe<VariableQualifier> variable_qualifier();
   /// Parses a `type_alias` grammar element
   /// @returns the type alias or nullptr on error
   Maybe<ast::Alias*> type_alias();
@@ -438,8 +456,10 @@
   /// @returns the parsed function, nullptr otherwise
   Maybe<ast::Function*> function_decl(ast::DecorationList& decos);
   /// Parses a `texture_sampler_types` grammar element
+  /// TODO(crbug.com/tint/864): Remove decos parameter
+  /// @param decos the list of decorations for the type declaration.
   /// @returns the parsed Type or nullptr if none matched.
-  Maybe<ast::Type*> texture_sampler_types();
+  Maybe<ast::Type*> texture_sampler_types(ast::DecorationList& decos);
   /// Parses a `sampler_type` grammar element
   /// @returns the parsed Type or nullptr if none matched.
   Maybe<ast::Type*> sampler_type();
@@ -477,10 +497,11 @@
   /// not match a stage name.
   /// @returns the pipeline stage.
   Expect<ast::PipelineStage> expect_pipeline_stage();
-  /// Parses an access type identifier, erroring if the next token does not
-  /// match a valid access type name.
+  /// Parses an access control identifier, erroring if the next token does not
+  /// match a valid access control.
+  /// @param use a description of what was being parsed if an error was raised
   /// @returns the parsed access control.
-  Expect<ast::AccessControl::Access> expect_access_type();
+  Expect<ast::Access> expect_access(const std::string& use);
   /// Parses a builtin identifier, erroring if the next token does not match a
   /// valid builtin name.
   /// @returns the parsed builtin.
diff --git a/src/reader/wgsl/parser_impl_error_msg_test.cc b/src/reader/wgsl/parser_impl_error_msg_test.cc
index dfb4c7f..0de7480 100644
--- a/src/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/reader/wgsl/parser_impl_error_msg_test.cc
@@ -548,31 +548,31 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingLessThan) {
-  EXPECT("var x : [[access(read)]] texture_storage_2d;",
-         "test.wgsl:1:44 error: expected '<' for storage texture type\n"
-         "var x : [[access(read)]] texture_storage_2d;\n"
-         "                                           ^\n");
+  EXPECT("var x : texture_storage_2d;",
+         "test.wgsl:1:27 error: expected '<' for storage texture type\n"
+         "var x : texture_storage_2d;\n"
+         "                          ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingGreaterThan) {
-  EXPECT("var x : [[access(read)]] texture_storage_2d<r8uint, read;",
-         "test.wgsl:1:57 error: expected '>' for storage texture type\n"
-         "var x : [[access(read)]] texture_storage_2d<r8uint, read;\n"
-         "                                                        ^\n");
+  EXPECT("var x : texture_storage_2d<r8uint, read;",
+         "test.wgsl:1:40 error: expected '>' for storage texture type\n"
+         "var x : texture_storage_2d<r8uint, read;\n"
+         "                                       ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingSubtype) {
-  EXPECT("var x : [[access(read)]] texture_storage_2d<>;",
-         "test.wgsl:1:45 error: invalid format for storage texture type\n"
-         "var x : [[access(read)]] texture_storage_2d<>;\n"
-         "                                            ^\n");
+  EXPECT("var x : texture_storage_2d<>;",
+         "test.wgsl:1:28 error: invalid format for storage texture type\n"
+         "var x : texture_storage_2d<>;\n"
+         "                           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingInvalidSubtype) {
-  EXPECT("var x : [[access(read)]] texture_storage_2d<1>;",
-         "test.wgsl:1:45 error: invalid format for storage texture type\n"
-         "var x : [[access(read)]] texture_storage_2d<1>;\n"
-         "                                            ^\n");
+  EXPECT("var x : texture_storage_2d<1>;",
+         "test.wgsl:1:28 error: invalid format for storage texture type\n"
+         "var x : texture_storage_2d<1>;\n"
+         "                           ^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDecoMissingStruct) {
@@ -1018,14 +1018,14 @@
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
   EXPECT("var<fish> i : i32",
-         "test.wgsl:1:5 error: invalid storage class for variable decoration\n"
+         "test.wgsl:1:5 error: invalid storage class for variable declaration\n"
          "var<fish> i : i32\n"
          "    ^^^^\n");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclMissingGThan) {
   EXPECT("var<in i : i32",
-         "test.wgsl:1:8 error: expected '>' for variable decoration\n"
+         "test.wgsl:1:8 error: expected '>' for variable declaration\n"
          "var<in i : i32\n"
          "       ^\n");
 }
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 7887b02..a57fbb6 100644
--- a/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -165,7 +165,7 @@
   EXPECT_TRUE(e.errored);
   EXPECT_FALSE(e.matched);
   EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
+  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_StorageClassIn_Deprecated) {
diff --git a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
index a574a06..76a0528 100644
--- a/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
+++ b/src/reader/wgsl/parser_impl_texture_sampler_types_test.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include "src/ast/access_decoration.h"
 #include "src/reader/wgsl/parser_impl_test_helper.h"
 #include "src/sem/depth_texture_type.h"
 #include "src/sem/multisampled_texture_type.h"
@@ -24,7 +25,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
   auto p = parser("1234");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -33,7 +35,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
   auto p = parser("sampler");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -45,7 +48,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
   auto p = parser("sampler_comparison");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -57,7 +61,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
   auto p = parser("texture_depth_2d");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -70,7 +75,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
   auto p = parser("texture_1d<f32>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -84,7 +90,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
   auto p = parser("texture_2d<i32>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -98,7 +105,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
   auto p = parser("texture_3d<u32>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -112,7 +120,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_Invalid) {
   auto p = parser("texture_1d<abc>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -122,7 +131,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
   auto p = parser("texture_1d<>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -132,7 +142,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
   auto p = parser("texture_1d");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -142,7 +153,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
   auto p = parser("texture_1d<u32");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -152,7 +164,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
   auto p = parser("texture_multisampled_2d<i32>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -166,7 +179,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_Invalid) {
   auto p = parser("texture_multisampled_2d<abc>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -176,7 +190,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
   auto p = parser("texture_multisampled_2d<>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_TRUE(p->has_error());
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
@@ -187,7 +202,8 @@
 TEST_F(ParserImplTest,
        TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
   auto p = parser("texture_multisampled_2d");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -197,7 +213,8 @@
 TEST_F(ParserImplTest,
        TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
   auto p = parser("texture_multisampled_2d<u32");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -208,7 +225,8 @@
 TEST_F(ParserImplTest,
        TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm_DEPRECATED) {
   auto p = parser("texture_storage_1d<r8unorm>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos{create<ast::AccessDecoration>(ast::Access::kRead)};
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -218,26 +236,25 @@
   ASSERT_TRUE(t->Is<ast::StorageTexture>());
   EXPECT_EQ(t->As<ast::StorageTexture>()->image_format(),
             ast::ImageFormat::kR8Unorm);
+  EXPECT_EQ(t->As<ast::StorageTexture>()->access(), ast::Access::kRead);
   EXPECT_EQ(t->As<ast::Texture>()->dim(), ast::TextureDimension::k1d);
   EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 28u}}));
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dR8Unorm) {
   auto p = parser("texture_storage_1d<r8unorm, read>");
-  auto a = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(a.matched);
-  EXPECT_FALSE(a.errored);
-  ASSERT_NE(a.value, nullptr);
+  EXPECT_TRUE(t.matched);
+  EXPECT_FALSE(t.errored);
+  ASSERT_NE(t.value, nullptr);
 
-  ASSERT_TRUE(a->Is<ast::AccessControl>());
-  EXPECT_TRUE(a->As<ast::AccessControl>()->IsReadOnly());
-
-  auto* t = a->As<ast::AccessControl>()->type();
   ASSERT_TRUE(t->Is<ast::Texture>());
   ASSERT_TRUE(t->Is<ast::StorageTexture>());
   EXPECT_EQ(t->As<ast::StorageTexture>()->image_format(),
             ast::ImageFormat::kR8Unorm);
+  EXPECT_EQ(t->As<ast::StorageTexture>()->access(), ast::Access::kRead);
   EXPECT_EQ(t->As<ast::Texture>()->dim(), ast::TextureDimension::k1d);
   EXPECT_EQ(t->source().range, (Source::Range{{1u, 1u}, {1u, 34u}}));
 }
@@ -246,7 +263,8 @@
 TEST_F(ParserImplTest,
        TextureSamplerTypes_StorageTexture_Writeonly2dR16Float_DEPRECATED) {
   auto p = parser("texture_storage_2d<r16float>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos{create<ast::AccessDecoration>(ast::Access::kWrite)};
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
   EXPECT_TRUE(t.matched);
   EXPECT_FALSE(t.errored);
@@ -256,33 +274,33 @@
   ASSERT_TRUE(t->Is<ast::StorageTexture>());
   EXPECT_EQ(t->As<ast::StorageTexture>()->image_format(),
             ast::ImageFormat::kR16Float);
+  EXPECT_EQ(t->As<ast::StorageTexture>()->access(), ast::Access::kWrite);
   EXPECT_EQ(t->As<ast::Texture>()->dim(), ast::TextureDimension::k2d);
   EXPECT_EQ(t.value->source().range, (Source::Range{{1u, 1u}, {1u, 29u}}));
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR16Float) {
   auto p = parser("texture_storage_2d<r16float, write>");
-  auto a = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(a.matched);
-  EXPECT_FALSE(a.errored);
-  ASSERT_NE(a.value, nullptr);
+  EXPECT_TRUE(t.matched);
+  EXPECT_FALSE(t.errored);
+  ASSERT_NE(t.value, nullptr);
 
-  ASSERT_TRUE(a->Is<ast::AccessControl>());
-  EXPECT_TRUE(a->As<ast::AccessControl>()->IsWriteOnly());
-
-  auto* t = a->As<ast::AccessControl>()->type();
   ASSERT_TRUE(t->Is<ast::Texture>());
   ASSERT_TRUE(t->Is<ast::StorageTexture>());
   EXPECT_EQ(t->As<ast::StorageTexture>()->image_format(),
             ast::ImageFormat::kR16Float);
+  EXPECT_EQ(t->As<ast::StorageTexture>()->access(), ast::Access::kWrite);
   EXPECT_EQ(t->As<ast::Texture>()->dim(), ast::TextureDimension::k2d);
   EXPECT_EQ(t->source().range, (Source::Range{{1u, 1u}, {1u, 36u}}));
 }
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
   auto p = parser("texture_storage_1d<abc, read>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -291,7 +309,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
   auto p = parser("texture_storage_1d<r16float, abc>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -300,7 +319,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
   auto p = parser("texture_storage_1d<>");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -309,7 +329,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
   auto p = parser("texture_storage_1d");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
@@ -318,7 +339,8 @@
 
 TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
   auto p = parser("texture_storage_1d<r8unorm, read");
-  auto t = p->texture_sampler_types();
+  ast::DecorationList decos;
+  auto t = p->texture_sampler_types(decos);
   EXPECT_EQ(t.value, nullptr);
   EXPECT_FALSE(t.matched);
   EXPECT_TRUE(t.errored);
diff --git a/src/reader/wgsl/parser_impl_variable_decl_test.cc b/src/reader/wgsl/parser_impl_variable_decl_test.cc
index 367b3d4..efb91d8 100644
--- a/src/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -87,7 +87,7 @@
   EXPECT_FALSE(v.matched);
   EXPECT_TRUE(v.errored);
   EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable decoration");
+  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
 }
 
 }  // namespace
diff --git a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
index 35cd419..59b8b83 100644
--- a/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
+++ b/src/reader/wgsl/parser_impl_variable_ident_decl_test.cc
@@ -84,7 +84,9 @@
   ASSERT_EQ(p->error(), "1:10: unknown constructed type 'invalid'");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithTextureAccessDeco_Read) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest,
+       VariableIdentDecl_ParsesWithTextureAccessDeco_Read_DEPRECATED) {
   auto p = parser("my_var : [[access(read)]] texture_storage_1d<r32float>");
 
   auto decl = p->expect_variable_ident_decl("test");
@@ -92,13 +94,17 @@
   ASSERT_FALSE(decl.errored);
   ASSERT_EQ(decl->name, "my_var");
   ASSERT_NE(decl->type, nullptr);
-  ASSERT_TRUE(decl->type->Is<ast::AccessControl>());
-  EXPECT_TRUE(decl->type->As<ast::AccessControl>()->IsReadOnly());
-  ASSERT_TRUE(
-      decl->type->As<ast::AccessControl>()->type()->Is<ast::StorageTexture>());
+  ASSERT_TRUE(decl->type->Is<ast::StorageTexture>());
+  EXPECT_TRUE(decl->type->As<ast::StorageTexture>()->is_read_only());
+
+  EXPECT_EQ(p->error(),
+            "1:54: use of deprecated language feature: access control is "
+            "expected as last parameter of storage textures");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithTextureAccessDeco_Write) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest,
+       VariableIdentDecl_ParsesWithTextureAccessDeco_Write_DEPRECATED) {
   auto p = parser("my_var : [[access(write)]] texture_storage_1d<r32float>");
 
   auto decl = p->expect_variable_ident_decl("test");
@@ -106,14 +112,17 @@
   ASSERT_FALSE(decl.errored);
   ASSERT_EQ(decl->name, "my_var");
   ASSERT_NE(decl->type, nullptr);
-  ASSERT_TRUE(decl->type->Is<ast::AccessControl>());
-  EXPECT_TRUE(decl->type->As<ast::AccessControl>()->IsWriteOnly());
-  ASSERT_TRUE(
-      decl->type->As<ast::AccessControl>()->type()->Is<ast::StorageTexture>());
+  ASSERT_TRUE(decl->type->Is<ast::StorageTexture>());
+  EXPECT_TRUE(decl->type->As<ast::StorageTexture>()->is_write_only());
+
+  EXPECT_EQ(p->error(),
+            "1:55: use of deprecated language feature: access control is "
+            "expected as last parameter of storage textures");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_Read) {
-  auto p = parser("my_var : [[access(read)]] S");
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_Read_DEPRECATED) {
+  auto p = parser("var my_var : [[access(read)]] S;");
 
   auto* mem = Member("a", ty.i32(), ast::DecorationList{});
   ast::StructMemberList members;
@@ -127,17 +136,25 @@
 
   p->register_constructed("S", s);
 
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(decl.errored);
-  ASSERT_EQ(decl->name, "my_var");
-  ASSERT_NE(decl->type, nullptr);
-  ASSERT_TRUE(decl->type->Is<ast::AccessControl>());
-  EXPECT_TRUE(decl->type->As<ast::AccessControl>()->IsReadOnly());
+  auto res = p->expect_global_decl();
+  ASSERT_FALSE(res.errored) << p->error();
+  ASSERT_NE(p->builder().AST().GlobalVariables().size(), 0u);
+  auto* decl = p->builder().AST().GlobalVariables()[0];
+  ASSERT_NE(decl, nullptr);
+  ASSERT_EQ(decl->symbol(), p->builder().Symbols().Get("my_var"));
+  ASSERT_NE(decl->type(), nullptr);
+  EXPECT_TRUE(decl->type()->Is<ast::TypeName>());
+  EXPECT_EQ(decl->declared_access(), ast::Access::kRead);
+
+  EXPECT_EQ(p->error(),
+            "1:1: use of deprecated language feature: declare access with "
+            "var<none, read> instead of using [[access]] decoration");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_ParsesWithAccessDeco_ReadWrite) {
-  auto p = parser("my_var : [[access(read_write)]] S");
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest,
+       VariableIdentDecl_ParsesWithAccessDeco_ReadWrite_DEPRECATED) {
+  auto p = parser("var my_var : [[access(read_write)]] S;");
 
   auto* mem = Member("a", ty.i32(), ast::DecorationList{});
   ast::StructMemberList members;
@@ -151,16 +168,23 @@
 
   p->register_constructed("S", s);
 
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(decl.errored);
-  ASSERT_EQ(decl->name, "my_var");
-  ASSERT_NE(decl->type, nullptr);
-  ASSERT_TRUE(decl->type->Is<ast::AccessControl>());
-  EXPECT_TRUE(decl->type->As<ast::AccessControl>()->IsReadWrite());
+  auto res = p->expect_global_decl();
+  ASSERT_FALSE(res.errored) << p->error();
+  ASSERT_NE(p->builder().AST().GlobalVariables().size(), 0u);
+  auto* decl = p->builder().AST().GlobalVariables()[0];
+  ASSERT_NE(decl, nullptr);
+  ASSERT_EQ(decl->symbol(), p->builder().Symbols().Get("my_var"));
+  ASSERT_NE(decl->type(), nullptr);
+  EXPECT_TRUE(decl->type()->Is<ast::TypeName>());
+  EXPECT_EQ(decl->declared_access(), ast::Access::kReadWrite);
+
+  EXPECT_EQ(p->error(),
+            "1:1: use of deprecated language feature: declare access with "
+            "var<none, read_write> instead of using [[access]] decoration");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDecoFail) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDecoFail_DEPRECATED) {
   auto p = parser("my_var : [[access(read), access(read_write)]] S");
 
   auto* mem = Member("a", ty.i32(), ast::DecorationList{});
@@ -181,7 +205,9 @@
   ASSERT_EQ(p->error(), "1:1: multiple access decorations not allowed");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_MultipleAccessDeco_MultiBlock_Fail) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest,
+       VariableIdentDecl_MultipleAccessDeco_MultiBlock_Fail_DEPRECATED) {
   auto p = parser("my_var : [[access(read)]][[access(read_write)]] S");
 
   auto* mem = Member("a", ty.i32(), ast::DecorationList{});
@@ -202,7 +228,8 @@
   ASSERT_EQ(p->error(), "1:1: multiple access decorations not allowed");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_AccessDecoBadValue) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest, VariableIdentDecl_AccessDecoBadValue_DEPRECATED) {
   auto p = parser("my_var : [[access(unknown)]] S");
   auto decl = p->expect_variable_ident_decl("test");
   ASSERT_TRUE(p->has_error());
@@ -210,12 +237,13 @@
   ASSERT_EQ(p->error(), "1:19: invalid value for access decoration");
 }
 
-TEST_F(ParserImplTest, VariableIdentDecl_AccessDecoIllegalValue) {
+// TODO(crbug.com/tint/846): Remove
+TEST_F(ParserImplTest, VariableIdentDecl_AccessDecoIllegalValue_DEPRECATED) {
   auto p = parser("my_var : [[access(1)]] S");
   auto decl = p->expect_variable_ident_decl("test");
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:19: expected identifier for access_type");
+  ASSERT_EQ(p->error(), "1:19: expected identifier for access control");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_NonAccessDecoFail) {
@@ -240,27 +268,27 @@
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_DecorationMissingRightBlock) {
-  auto p = parser("my_var : [[access(read) S");
+  auto p = parser("my_var : [[stride(4) S");
   auto decl = p->expect_variable_ident_decl("test");
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:25: expected ']]' for decoration list");
+  ASSERT_EQ(p->error(), "1:22: expected ']]' for decoration list");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_DecorationMissingRightParen) {
-  auto p = parser("my_var : [[access(read]] S");
+  auto p = parser("my_var : [[stride(4]] S");
   auto decl = p->expect_variable_ident_decl("test");
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:23: expected ')' for access decoration");
+  ASSERT_EQ(p->error(), "1:20: expected ')' for stride decoration");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_DecorationMissingLeftParen) {
-  auto p = parser("my_var : [[access read)]] S");
+  auto p = parser("my_var : [[stride 4)]] S");
   auto decl = p->expect_variable_ident_decl("test");
   ASSERT_TRUE(p->has_error());
   ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:19: expected '(' for access decoration");
+  ASSERT_EQ(p->error(), "1:19: expected '(' for stride decoration");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_DecorationEmpty) {
diff --git a/src/reader/wgsl/parser_impl_variable_qualifier_test.cc b/src/reader/wgsl/parser_impl_variable_qualifier_test.cc
new file mode 100644
index 0000000..b070d24
--- /dev/null
+++ b/src/reader/wgsl/parser_impl_variable_qualifier_test.cc
@@ -0,0 +1,130 @@
+// 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/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint {
+namespace reader {
+namespace wgsl {
+namespace {
+
+struct VariableStorageData {
+  const char* input;
+  ast::StorageClass storage_class;
+  ast::Access access;
+};
+inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
+  out << std::string(data.input);
+  return out;
+}
+
+class VariableQualifierTest
+    : public ParserImplTestWithParam<VariableStorageData> {};
+
+TEST_P(VariableQualifierTest, ParsesStorageClass) {
+  auto params = GetParam();
+  auto p = parser(std::string("<") + params.input + ">");
+
+  auto sc = p->variable_qualifier();
+  EXPECT_FALSE(p->has_error());
+  EXPECT_FALSE(sc.errored);
+  EXPECT_TRUE(sc.matched);
+  EXPECT_EQ(sc->storage_class, params.storage_class);
+  EXPECT_EQ(sc->access, params.access);
+
+  auto t = p->next();
+  EXPECT_TRUE(t.IsEof());
+}
+INSTANTIATE_TEST_SUITE_P(
+    ParserImplTest,
+    VariableQualifierTest,
+    testing::Values(
+        VariableStorageData{"in", ast::StorageClass::kInput,
+                            ast::Access::kUndefined},
+        VariableStorageData{"out", ast::StorageClass::kOutput,
+                            ast::Access::kUndefined},
+        VariableStorageData{"uniform", ast::StorageClass::kUniform,
+                            ast::Access::kUndefined},
+        VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup,
+                            ast::Access::kUndefined},
+        VariableStorageData{"storage", ast::StorageClass::kStorage,
+                            ast::Access::kUndefined},
+        VariableStorageData{"storage_buffer", ast::StorageClass::kStorage,
+                            ast::Access::kUndefined},
+        VariableStorageData{"image", ast::StorageClass::kImage,
+                            ast::Access::kUndefined},
+        VariableStorageData{"private", ast::StorageClass::kPrivate,
+                            ast::Access::kUndefined},
+        VariableStorageData{"function", ast::StorageClass::kFunction,
+                            ast::Access::kUndefined},
+        VariableStorageData{"storage, read", ast::StorageClass::kStorage,
+                            ast::Access::kRead},
+        VariableStorageData{"storage, write", ast::StorageClass::kStorage,
+                            ast::Access::kWrite},
+        VariableStorageData{"storage, read_write", ast::StorageClass::kStorage,
+                            ast::Access::kReadWrite}));
+
+TEST_F(ParserImplTest, VariableQualifier_NoMatch) {
+  auto p = parser("<not-a-storage-class>");
+  auto sc = p->variable_qualifier();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(sc.errored);
+  EXPECT_FALSE(sc.matched);
+  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
+}
+
+TEST_F(ParserImplTest, VariableQualifier_Empty) {
+  auto p = parser("<>");
+  auto sc = p->variable_qualifier();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(sc.errored);
+  EXPECT_FALSE(sc.matched);
+  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
+}
+
+TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
+  auto p = parser("in>");
+  auto sc = p->variable_qualifier();
+  EXPECT_FALSE(p->has_error());
+  EXPECT_FALSE(sc.errored);
+  EXPECT_FALSE(sc.matched);
+
+  auto t = p->next();
+  ASSERT_TRUE(t.IsIn());
+}
+
+TEST_F(ParserImplTest, VariableQualifier_MissingLessThan_AfterSC) {
+  auto p = parser("in, >");
+  auto sc = p->variable_qualifier();
+  EXPECT_FALSE(p->has_error());
+  EXPECT_FALSE(sc.errored);
+  EXPECT_FALSE(sc.matched);
+
+  auto t = p->next();
+  ASSERT_TRUE(t.IsIn());
+}
+
+TEST_F(ParserImplTest, VariableQualifier_MissingGreaterThan) {
+  auto p = parser("<in");
+  auto sc = p->variable_qualifier();
+  EXPECT_TRUE(p->has_error());
+  EXPECT_TRUE(sc.errored);
+  EXPECT_FALSE(sc.matched);
+  EXPECT_EQ(p->error(), "1:4: expected '>' for variable declaration");
+}
+
+}  // namespace
+}  // namespace wgsl
+}  // namespace reader
+}  // namespace tint
diff --git a/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc b/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc
deleted file mode 100644
index 889f631..0000000
--- a/src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc
+++ /dev/null
@@ -1,102 +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/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint {
-namespace reader {
-namespace wgsl {
-namespace {
-
-struct VariableStorageData {
-  const char* input;
-  ast::StorageClass result;
-};
-inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
-  out << std::string(data.input);
-  return out;
-}
-
-class VariableStorageTest
-    : public ParserImplTestWithParam<VariableStorageData> {};
-
-TEST_P(VariableStorageTest, Parses) {
-  auto params = GetParam();
-  auto p = parser(std::string("<") + params.input + ">");
-
-  auto sc = p->variable_storage_decoration();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(sc.errored);
-  EXPECT_TRUE(sc.matched);
-  EXPECT_EQ(sc.value, params.result);
-
-  auto t = p->next();
-  EXPECT_TRUE(t.IsEof());
-}
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplTest,
-    VariableStorageTest,
-    testing::Values(
-        VariableStorageData{"in", ast::StorageClass::kInput},
-        VariableStorageData{"out", ast::StorageClass::kOutput},
-        VariableStorageData{"uniform", ast::StorageClass::kUniform},
-        VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup},
-        VariableStorageData{"storage", ast::StorageClass::kStorage},
-        VariableStorageData{"storage_buffer", ast::StorageClass::kStorage},
-        VariableStorageData{"image", ast::StorageClass::kImage},
-        VariableStorageData{"private", ast::StorageClass::kPrivate},
-        VariableStorageData{"function", ast::StorageClass::kFunction}));
-
-TEST_F(ParserImplTest, VariableStorageDecoration_NoMatch) {
-  auto p = parser("<not-a-storage-class>");
-  auto sc = p->variable_storage_decoration();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
-}
-
-TEST_F(ParserImplTest, VariableStorageDecoration_Empty) {
-  auto p = parser("<>");
-  auto sc = p->variable_storage_decoration();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable decoration");
-}
-
-TEST_F(ParserImplTest, VariableStorageDecoration_MissingLessThan) {
-  auto p = parser("in>");
-  auto sc = p->variable_storage_decoration();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-
-  auto t = p->next();
-  ASSERT_TRUE(t.IsIn());
-}
-
-TEST_F(ParserImplTest, VariableStorageDecoration_MissingGreaterThan) {
-  auto p = parser("<in");
-  auto sc = p->variable_storage_decoration();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:4: expected '>' for variable decoration");
-}
-
-}  // namespace
-}  // namespace wgsl
-}  // namespace reader
-}  // namespace tint
diff --git a/src/resolver/assignment_validation_test.cc b/src/resolver/assignment_validation_test.cc
index dab2610..b908662 100644
--- a/src/resolver/assignment_validation_test.cc
+++ b/src/resolver/assignment_validation_test.cc
@@ -156,14 +156,14 @@
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignNonStorable_Fail) {
-  // var a : [[access(read)]] texture_storage_1d<rgba8unorm>;
-  // var b : [[access(read)]] texture_storage_1d<rgba8unorm>;
+  // var a : texture_storage_1d<rgba8unorm, read>;
+  // var b : texture_storage_1d<rgba8unorm, read>;
   // a = b;
 
   auto make_type = [&] {
-    auto* tex_type = ty.storage_texture(ast::TextureDimension::k1d,
-                                        ast::ImageFormat::kRgba8Unorm);
-    return ty.access(ast::AccessControl::kRead, tex_type);
+    return ty.storage_texture(ast::TextureDimension::k1d,
+                              ast::ImageFormat::kRgba8Unorm,
+                              ast::Access::kRead);
   };
 
   Global("a", make_type(), ast::StorageClass::kNone,
@@ -182,7 +182,7 @@
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(
       r()->error(),
-      R"(12:34 error: '[[access(read)]] texture_storage_1d<rgba8unorm>' is not storable)");
+      R"(12:34 error: 'texture_storage_1d<rgba8unorm, read>' is not storable)");
 }
 
 }  // namespace
diff --git a/src/resolver/decoration_validation_test.cc b/src/resolver/decoration_validation_test.cc
index e24dc70..1de719b 100644
--- a/src/resolver/decoration_validation_test.cc
+++ b/src/resolver/decoration_validation_test.cc
@@ -30,7 +30,6 @@
 namespace {
 
 enum class DecorationKind {
-  kAccess,
   kAlign,
   kBinding,
   kBuiltin,
@@ -68,9 +67,6 @@
                                              ProgramBuilder& builder,
                                              DecorationKind kind) {
   switch (kind) {
-    case DecorationKind::kAccess:
-      return {builder.create<ast::AccessDecoration>(source,
-                                                    ast::AccessControl::kRead)};
     case DecorationKind::kAlign:
       return {builder.create<ast::StructMemberAlignDecoration>(source, 4u)};
     case DecorationKind::kBinding:
@@ -122,8 +118,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     FunctionReturnTypeDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
                     TestParams{DecorationKind::kGroup, false},
@@ -162,8 +157,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     ArrayDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
                     TestParams{DecorationKind::kGroup, false},
@@ -197,8 +191,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     StructDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
                     TestParams{DecorationKind::kGroup, false},
@@ -234,8 +227,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     StructMemberDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, true},
+    testing::Values(TestParams{DecorationKind::kAlign, true},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
                     TestParams{DecorationKind::kGroup, false},
@@ -277,8 +269,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     VariableDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, true},
                     TestParams{DecorationKind::kGroup, false},
@@ -312,8 +303,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     ConstantDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
                     TestParams{DecorationKind::kGroup, false},
@@ -346,8 +336,7 @@
 INSTANTIATE_TEST_SUITE_P(
     ResolverDecorationValidationTest,
     FunctionDecorationTest,
-    testing::Values(TestParams{DecorationKind::kAccess, false},
-                    TestParams{DecorationKind::kAlign, false},
+    testing::Values(TestParams{DecorationKind::kAlign, false},
                     TestParams{DecorationKind::kBinding, false},
                     TestParams{DecorationKind::kBuiltin, false},
                     TestParams{DecorationKind::kGroup, false},
@@ -523,8 +512,8 @@
 TEST_F(ResourceDecorationTest, StorageBufferMissingBinding) {
   auto* s = Structure("S", {Member("x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{12, 34}}, "G", ac, ast::StorageClass::kStorage);
+  Global(Source{{12, 34}}, "G", s, ast::StorageClass::kStorage,
+         ast::Access::kRead);
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
diff --git a/src/resolver/host_shareable_validation_test.cc b/src/resolver/host_shareable_validation_test.cc
index bb73ad9..57e6fbc 100644
--- a/src/resolver/host_shareable_validation_test.cc
+++ b/src/resolver/host_shareable_validation_test.cc
@@ -28,8 +28,9 @@
 TEST_F(ResolverHostShareableValidationTest, BoolMember) {
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -47,8 +48,9 @@
 TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -68,10 +70,10 @@
   AST().AddConstructedType(a1);
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", a1)},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-  auto* a2 = ty.alias("a2", ac);
+  auto* a2 = ty.alias("a2", s);
   AST().AddConstructedType(a2);
   Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -93,8 +95,9 @@
 
   auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage,
+
+  Global(Source{{9, 10}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -135,8 +138,9 @@
 
   auto* s = Structure("S", {Member(Source{{7, 8}}, "m", i3)},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{9, 10}}, "g", a, ast::StorageClass::kStorage,
+
+  Global(Source{{9, 10}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/resolver/intrinsic_test.cc b/src/resolver/intrinsic_test.cc
index 701796f..39d1b18 100644
--- a/src/resolver/intrinsic_test.cc
+++ b/src/resolver/intrinsic_test.cc
@@ -276,12 +276,11 @@
   auto format = GetParam().format;
 
   auto* coords_type = GetCoordsType(dim, ty.i32());
-  auto* texture_type = ty.storage_texture(dim, format);
-  auto* ro_texture_type = ty.access(ast::AccessControl::kRead, texture_type);
+  auto* texture_type = ty.storage_texture(dim, format, ast::Access::kRead);
 
   ast::ExpressionList call_params;
 
-  add_call_param("texture", ro_texture_type, &call_params);
+  add_call_param("texture", texture_type, &call_params);
   add_call_param("coords", coords_type, &call_params);
 
   if (ast::IsTextureArray(dim)) {
@@ -769,8 +768,7 @@
   auto* ary = ty.array<i32>();
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage,
+  Global("a", str, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/resolver/resolver.cc b/src/resolver/resolver.cc
index 9f81e32..14f4b7d 100644
--- a/src/resolver/resolver.cc
+++ b/src/resolver/resolver.cc
@@ -287,13 +287,6 @@
     if (ty->Is<ast::F32>()) {
       return builder_->create<sem::F32>();
     }
-    if (auto* t = ty->As<ast::AccessControl>()) {
-      TINT_SCOPED_ASSIGNMENT(current_access_control_, t);
-      if (auto* el = Type(t->type())) {
-        return el;
-      }
-      return nullptr;
-    }
     if (auto* t = ty->As<ast::Vector>()) {
       if (auto* el = Type(t->type())) {
         return builder_->create<sem::Vector>(const_cast<sem::Type*>(el),
@@ -341,14 +334,11 @@
     }
     if (auto* t = ty->As<ast::StorageTexture>()) {
       if (auto* el = Type(t->type())) {
-        if (!current_access_control_) {
-          diagnostics_.add_error("storage textures must have access control",
-                                 t->source());
+        if (!ValidateStorageTexture(t)) {
           return nullptr;
         }
         return builder_->create<sem::StorageTexture>(
-            t->dim(), t->image_format(),
-            current_access_control_->access_control(),
+            t->dim(), t->image_format(), t->access(),
             const_cast<sem::Type*>(el));
       }
       return nullptr;
@@ -377,6 +367,39 @@
   return s;
 }
 
+bool Resolver::ValidateStorageTexture(const ast::StorageTexture* t) {
+  switch (t->access()) {
+    case ast::Access::kUndefined:
+      diagnostics_.add_error("storage textures must have access control",
+                             t->source());
+      return false;
+    case ast::Access::kReadWrite:
+      diagnostics_.add_error(
+          "storage textures only support read-only and write-only access",
+          t->source());
+      return false;
+
+    case ast::Access::kRead:
+    case ast::Access::kWrite:
+      break;
+  }
+
+  if (!IsValidStorageTextureDimension(t->dim())) {
+    diagnostics_.add_error(
+        "cube dimensions for storage textures are not supported", t->source());
+    return false;
+  }
+
+  if (!IsValidStorageTextureImageFormat(t->image_format())) {
+    diagnostics_.add_error(
+        "image format must be one of the texel formats specified for storage "
+        "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
+        t->source());
+    return false;
+  }
+  return true;
+}
+
 Resolver::VariableInfo* Resolver::Variable(ast::Variable* var,
                                            VariableKind kind) {
   if (variable_to_info_.count(var)) {
@@ -466,35 +489,17 @@
     return nullptr;
   }
 
-  // TODO(crbug.com/tint/802): Temporary while ast::AccessControl exits.
-  auto find_first_access_control =
-      [this](const ast::Type* ty) -> const ast::AccessControl* {
-    if (ty == nullptr) {
-      return nullptr;
-    }
-    if (const ast::AccessControl* ac = ty->As<ast::AccessControl>()) {
-      return ac;
-    }
-    while (auto* tn = ty->As<ast::TypeName>()) {
-      auto it = named_type_info_.find(tn->name());
-      if (it == named_type_info_.end()) {
-        break;
-      }
-      auto* alias = it->second.ast->As<ast::Alias>();
-      if (!alias) {
-        break;
-      }
-      ty = alias->type();
-      if (auto* ac = ty->As<ast::AccessControl>()) {
-        return ac;
-      }
-    }
-    return nullptr;
-  };
+  auto access = var->declared_access();
+  if (access == ast::Access::kUndefined &&
+      storage_class == ast::StorageClass::kStorage) {
+    // https://gpuweb.github.io/gpuweb/wgsl/#access-mode-defaults
+    // For the storage storage class, the access mode is optional, and defaults
+    // to read.
+    access = ast::Access::kRead;
+  }
 
-  auto* access_control = find_first_access_control(var->type());
   auto* info = variable_infos_.Create(var, const_cast<sem::Type*>(type),
-                                      type_name, storage_class, access_control);
+                                      type_name, storage_class, access);
   variable_to_info_.emplace(var, info);
 
   return info;
@@ -658,25 +663,31 @@
       }
   }
 
+  // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
+  // The access mode always has a default, and except for variables in the
+  // storage storage class, must not be written.
+  if (info->storage_class != ast::StorageClass::kStorage &&
+      info->declaration->declared_access() != ast::Access::kUndefined) {
+    diagnostics_.add_error(
+        "variables declared not declared in the <storage> storage class must "
+        "not declare an access control",
+        info->declaration->source());
+    return false;
+  }
+
   switch (info->storage_class) {
     case ast::StorageClass::kStorage: {
-      // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
-      // Variables in the storage storage class and variables with a storage
-      // texture type must have an access attribute applied to the store type.
-
       // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
       // A variable in the storage storage class is a storage buffer variable.
       // Its store type must be a host-shareable structure type with block
       // attribute, satisfying the storage class constraints.
 
-      auto* str = info->access_control
-                      ? info->type->UnwrapRef()->As<sem::Struct>()
-                      : nullptr;
+      auto* str = info->type->UnwrapRef()->As<sem::Struct>();
 
       if (!str) {
         diagnostics_.add_error(
-            "variables declared in the <storage> storage class must be of an "
-            "[[access]] qualified structure type",
+            "variables declared in the <storage> storage class must be of a "
+            "structure type",
             info->declaration->source());
         return false;
       }
@@ -756,33 +767,6 @@
     }
   }
 
-  if (auto* storage_tex = info->type->UnwrapRef()->As<sem::StorageTexture>()) {
-    if (info->access_control->access_control() ==
-        ast::AccessControl::kReadWrite) {
-      diagnostics_.add_error(
-          "storage textures only support read-only and write-only access",
-          var->source());
-      return false;
-    }
-
-    if (!IsValidStorageTextureDimension(storage_tex->dim())) {
-      diagnostics_.add_error(
-          "cube dimensions for storage textures are not "
-          "supported",
-          var->source());
-      return false;
-    }
-
-    if (!IsValidStorageTextureImageFormat(storage_tex->image_format())) {
-      diagnostics_.add_error(
-          "image format must be one of the texel formats specified for "
-          "storage textues in "
-          "https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
-          var->source());
-      return false;
-    }
-  }
-
   if (storage_type->is_handle() &&
       var->declared_storage_class() != ast::StorageClass::kNone) {
     // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
@@ -2584,9 +2568,7 @@
       sem_var = builder_->create<sem::Variable>(var, info->type, constant_id);
     } else {
       sem_var = builder_->create<sem::Variable>(
-          var, info->type, info->storage_class,
-          info->access_control ? info->access_control->access_control()
-                               : ast::AccessControl::kReadWrite);
+          var, info->type, info->storage_class, info->access);
     }
 
     std::vector<const sem::VariableUser*> users;
@@ -3274,12 +3256,12 @@
                                      sem::Type* ty,
                                      const std::string& tn,
                                      ast::StorageClass sc,
-                                     const ast::AccessControl* ac)
+                                     ast::Access ac)
     : declaration(decl),
       type(ty),
       type_name(tn),
       storage_class(sc),
-      access_control(ac) {}
+      access(ac) {}
 
 Resolver::VariableInfo::~VariableInfo() = default;
 
diff --git a/src/resolver/resolver.h b/src/resolver/resolver.h
index 2efdf7c..4b893bf 100644
--- a/src/resolver/resolver.h
+++ b/src/resolver/resolver.h
@@ -89,14 +89,14 @@
                  sem::Type* type,
                  const std::string& type_name,
                  ast::StorageClass storage_class,
-                 const ast::AccessControl* ac);
+                 ast::Access ac);
     ~VariableInfo();
 
     ast::Variable const* const declaration;
     sem::Type* type;
     std::string const type_name;
     ast::StorageClass storage_class;
-    ast::AccessControl const* const access_control;
+    ast::Access const access;
     std::vector<ast::IdentifierExpression*> users;
     sem::BindingPoint binding_point;
   };
@@ -255,6 +255,7 @@
                                  const sem::Matrix* matrix_type);
   bool ValidateParameter(const VariableInfo* info);
   bool ValidateReturn(const ast::ReturnStatement* ret);
+  bool ValidateStorageTexture(const ast::StorageTexture* t);
   bool ValidateStructure(const sem::Struct* str);
   bool ValidateSwitch(const ast::SwitchStatement* s);
   bool ValidateVariable(const VariableInfo* info);
@@ -394,7 +395,6 @@
 
   FunctionInfo* current_function_ = nullptr;
   sem::Statement* current_statement_ = nullptr;
-  const ast::AccessControl* current_access_control_ = nullptr;
   BlockAllocator<VariableInfo> variable_infos_;
   BlockAllocator<FunctionInfo> function_infos_;
 };
diff --git a/src/resolver/resolver_test.cc b/src/resolver/resolver_test.cc
index 84935c4..ba3ef08 100644
--- a/src/resolver/resolver_test.cc
+++ b/src/resolver/resolver_test.cc
@@ -784,15 +784,15 @@
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
   auto* s = Structure("S", {Member("m", ty.u32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
 
   auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
   auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
-  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage,
-                        ast::DecorationList{
-                            create<ast::BindingDecoration>(0),
-                            create<ast::GroupDecoration>(0),
-                        });
+  auto* sb_var =
+      Global("sb_var", s, ast::StorageClass::kStorage, ast::Access::kRead,
+             ast::DecorationList{
+                 create<ast::BindingDecoration>(0),
+                 create<ast::GroupDecoration>(0),
+             });
   auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
   auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
 
@@ -823,15 +823,15 @@
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
   auto* s = Structure("S", {Member("m", ty.u32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
 
   auto* in_var = Global("in_var", ty.f32(), ast::StorageClass::kInput);
   auto* out_var = Global("out_var", ty.f32(), ast::StorageClass::kOutput);
-  auto* sb_var = Global("sb_var", a, ast::StorageClass::kStorage,
-                        ast::DecorationList{
-                            create<ast::BindingDecoration>(0),
-                            create<ast::GroupDecoration>(0),
-                        });
+  auto* sb_var =
+      Global("sb_var", s, ast::StorageClass::kStorage, ast::Access::kRead,
+             ast::DecorationList{
+                 create<ast::BindingDecoration>(0),
+                 create<ast::GroupDecoration>(0),
+             });
   auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
   auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
 
@@ -1757,8 +1757,7 @@
 
 TEST_F(ResolverTest, StorageClass_SetForTexture) {
   auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  auto* ac = ty.access(ast::AccessControl::kRead, t);
-  auto* var = Global("var", ac,
+  auto* var = Global("var", t,
                      ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
@@ -1780,6 +1779,22 @@
   EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kNone);
 }
 
+TEST_F(ResolverTest, Access_SetForStorageBuffer) {
+  // [[block]] struct S { x : i32 };
+  // var<storage> g : S;
+  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
+                      {create<ast::StructBlockDecoration>()});
+  auto* var = Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+                     ast::DecorationList{
+                         create<ast::BindingDecoration>(0),
+                         create<ast::GroupDecoration>(0),
+                     });
+
+  EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+  EXPECT_EQ(Sem().Get(var)->Access(), ast::Access::kRead);
+}
+
 TEST_F(ResolverTest, Function_EntryPoints_StageDecoration) {
   // fn b() {}
   // fn c() { b(); }
diff --git a/src/resolver/resolver_test_helper.h b/src/resolver/resolver_test_helper.h
index 675fa33..3597e27 100644
--- a/src/resolver/resolver_test_helper.h
+++ b/src/resolver/resolver_test_helper.h
@@ -226,12 +226,6 @@
   return ty.builder->create<ast::TypeName>(name);
 }
 
-template <create_ast_type_func_ptr create_type>
-ast::Type* ast_access(const ProgramBuilder::TypesBuilder& ty) {
-  auto* type = create_type(ty);
-  return ty.access(ast::AccessControl::kRead, type);
-}
-
 inline sem::Type* sem_bool(const ProgramBuilder::TypesBuilder& ty) {
   return ty.builder->create<sem::Bool>();
 }
diff --git a/src/resolver/storage_class_validation_test.cc b/src/resolver/storage_class_validation_test.cc
index 67efdd7..29c8945 100644
--- a/src/resolver/storage_class_validation_test.cc
+++ b/src/resolver/storage_class_validation_test.cc
@@ -46,7 +46,7 @@
 
   EXPECT_EQ(
       r()->error(),
-      R"(56:78 error: variables declared in the <storage> storage class must be of an [[access]] qualified structure type)");
+      R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
@@ -62,15 +62,15 @@
 
   EXPECT_EQ(
       r()->error(),
-      R"(56:78 error: variables declared in the <storage> storage class must be of an [[access]] qualified structure type)");
+      R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
-  // var<storage> g : [[access(read)]] array<S, 3>;
+  // var<storage, read> g : array<S, 3>;
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
-  auto* ac = ty.access(ast::AccessControl::kRead, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kStorage,
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -80,12 +80,12 @@
 
   EXPECT_EQ(
       r()->error(),
-      R"(56:78 error: variables declared in the <storage> storage class must be of an [[access]] qualified structure type)");
+      R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
   // type a = bool;
-  // var<storage> g : [[access(read)]] a;
+  // var<storage, read> g : a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
   Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
@@ -98,31 +98,15 @@
 
   EXPECT_EQ(
       r()->error(),
-      R"(56:78 error: variables declared in the <storage> storage class must be of an [[access]] qualified structure type)");
-}
-
-TEST_F(ResolverStorageClassValidationTest, StorageBufferNoAccessControl) {
-  // var<storage> g : S;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
-         ast::DecorationList{
-             create<ast::BindingDecoration>(0),
-             create<ast::GroupDecoration>(0),
-         });
-
-  ASSERT_FALSE(r()->Resolve());
-
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: variables declared in the <storage> storage class must be of an [[access]] qualified structure type)");
+      R"(56:78 error: variables declared in the <storage> storage class must be of a structure type)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoBlockDecoration) {
   // struct S { x : i32 };
-  // var<storage> g : [[access(read)]] S;
+  // var<storage, read> g : S;
   auto* s = Structure(Source{{12, 34}}, "S", {Member("x", ty.i32())});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -138,11 +122,11 @@
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
   // [[block]] struct S { x : i32 };
-  // var<storage> g : [[access(read)]] S;
+  // var<storage, read> g : S;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
+  Global(Source{{56, 78}}, "g", s, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -154,16 +138,15 @@
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
   // [[block]] struct S { x : i32 };
   // type a1 = S;
-  // type a2 = [[access(read)]] a1;
-  // var<storage> g : a2;
+  // var<storage, read> g : a1;
   auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
   auto* a1 = ty.alias("a1", s);
   AST().AddConstructedType(a1);
-  auto* ac = ty.access(ast::AccessControl::kRead, a1);
-  auto* a2 = ty.alias("a2", ac);
+  auto* a2 = ty.alias("a2", a1);
   AST().AddConstructedType(a2);
   Global(Source{{56, 78}}, "g", a2, ast::StorageClass::kStorage,
+         ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -206,11 +189,10 @@
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
-  // var<uniform> g : [[access(read)]] array<S, 3>;
+  // var<uniform> g : array<S, 3>;
   auto* s = Structure("S", {Member("a", ty.f32())});
   auto* a = ty.array(s, 3);
-  auto* ac = ty.access(ast::AccessControl::kRead, a);
-  Global(Source{{56, 78}}, "g", ac, ast::StorageClass::kUniform,
+  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -225,7 +207,7 @@
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
   // type a = bool;
-  // var<uniform> g : [[access(read)]] a;
+  // var<uniform> g : a;
   auto* a = ty.alias("a", ty.bool_());
   AST().AddConstructedType(a);
   Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
diff --git a/src/resolver/struct_storage_class_use_test.cc b/src/resolver/struct_storage_class_use_test.cc
index 46fe48d..7a83ab0 100644
--- a/src/resolver/struct_storage_class_use_test.cc
+++ b/src/resolver/struct_storage_class_use_test.cc
@@ -172,13 +172,12 @@
 TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
   auto* s = Structure("S", {Member("a", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
   Global("x", s, ast::StorageClass::kUniform,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
-  Global("y", ac, ast::StorageClass::kStorage,
+  Global("y", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(0),
diff --git a/src/resolver/type_validation_test.cc b/src/resolver/type_validation_test.cc
index 38375f8..c7882c0 100644
--- a/src/resolver/type_validation_test.cc
+++ b/src/resolver/type_validation_test.cc
@@ -66,10 +66,10 @@
 
 TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) {
   // const<in> global_var: f32;
-  AST().AddGlobalVariable(
-      create<ast::Variable>(Source{{12, 34}}, Symbols().Register("global_var"),
-                            ast::StorageClass::kInput, ty.f32(), true,
-                            Expr(1.23f), ast::DecorationList{}));
+  AST().AddGlobalVariable(create<ast::Variable>(
+      Source{{12, 34}}, Symbols().Register("global_var"),
+      ast::StorageClass::kInput, ast::Access::kUndefined, ty.f32(), true,
+      Expr(1.23f), ast::DecorationList{}));
 
   EXPECT_FALSE(r()->Resolve());
   EXPECT_EQ(r()->error(),
@@ -393,11 +393,9 @@
     Params{ast_alias<ast_alias<ast_mat3x3<ast_alias<ast_alias<ast_f32>>>>>,
            sem_mat3x3<sem_f32>},
 
-    Params{ast_alias<ast_access<ast_alias<ast_bool>>>, sem_bool},
-    Params{ast_alias<ast_access<ast_alias<ast_vec3<ast_access<ast_f32>>>>>,
-           sem_vec3<sem_f32>},
-    Params{ast_alias<ast_access<ast_alias<ast_mat3x3<ast_access<ast_f32>>>>>,
-           sem_mat3x3<sem_f32>},
+    Params{ast_alias<ast_alias<ast_bool>>, sem_bool},
+    Params{ast_alias<ast_alias<ast_vec3<ast_f32>>>, sem_vec3<sem_f32>},
+    Params{ast_alias<ast_alias<ast_mat3x3<ast_f32>>>, sem_mat3x3<sem_f32>},
 };
 
 using CanonicalTest = ResolverTestWithParam<Params>;
@@ -526,13 +524,13 @@
 using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
 TEST_P(StorageTextureDimensionTest, All) {
   // [[group(0), binding(0)]]
-  // var a : [[access(read)]] texture_storage_*<ru32int>;
+  // var a : texture_storage_*<ru32int, read>;
   auto& params = GetParam();
 
-  auto* st = ty.storage_texture(params.dim, ast::ImageFormat::kR32Uint);
-  auto* ac = ty.access(ast::AccessControl::kRead, st);
+  auto* st = ty.storage_texture(Source{{12, 34}}, params.dim,
+                                ast::ImageFormat::kR32Uint, ast::Access::kRead);
 
-  Global(Source{{12, 34}}, "a", ac, ast::StorageClass::kNone, nullptr,
+  Global("a", st, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -597,42 +595,41 @@
 TEST_P(StorageTextureFormatTest, All) {
   auto& params = GetParam();
   // [[group(0), binding(0)]]
-  // var a : [[access(read)]] texture_storage_1d<*>;
+  // var a : texture_storage_1d<*, read>;
   // [[group(0), binding(1)]]
-  // var b : [[access(read)]] texture_storage_2d<*>;
+  // var b : texture_storage_2d<*, read>;
   // [[group(0), binding(2)]]
-  // var c : [[access(read)]] texture_storage_2d_array<*>;
+  // var c : texture_storage_2d_array<*, read>;
   // [[group(0), binding(3)]]
-  // var d : [[access(read)]] texture_storage_3d<*>;
+  // var d : texture_storage_3d<*, read>;
 
-  auto* st_a = ty.storage_texture(ast::TextureDimension::k1d, params.format);
-  auto* ac_a = ty.access(ast::AccessControl::kRead, st_a);
-  Global(Source{{12, 34}}, "a", ac_a, ast::StorageClass::kNone, nullptr,
+  auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                                  params.format, ast::Access::kRead);
+  Global("a", st_a, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
          });
 
-  auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format);
-  auto* ac_b = ty.access(ast::AccessControl::kRead, st_b);
-  Global("b", ac_b, ast::StorageClass::kNone, nullptr,
+  auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format,
+                                  ast::Access::kRead);
+  Global("b", st_b, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
          });
 
-  auto* st_c =
-      ty.storage_texture(ast::TextureDimension::k2dArray, params.format);
-  auto* ac_c = ty.access(ast::AccessControl::kRead, st_c);
-  Global("c", ac_c, ast::StorageClass::kNone, nullptr,
+  auto* st_c = ty.storage_texture(ast::TextureDimension::k2dArray,
+                                  params.format, ast::Access::kRead);
+  Global("c", st_c, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(2),
          });
 
-  auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format);
-  auto* ac_d = ty.access(ast::AccessControl::kRead, st_d);
-  Global("d", ac_d, ast::StorageClass::kNone, nullptr,
+  auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format,
+                                  ast::Access::kRead);
+  Global("d", st_d, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(3),
@@ -652,16 +649,17 @@
                          StorageTextureFormatTest,
                          testing::ValuesIn(format_cases));
 
-using StorageTextureAccessControlTest = ResolverTest;
+using StorageTextureAccessTest = ResolverTest;
 
-TEST_F(StorageTextureAccessControlTest, MissingAccessControl_Fail) {
+TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
   // [[group(0), binding(0)]]
   // var a : texture_storage_1d<ru32int>;
 
-  auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
-                                ast::ImageFormat::kR32Uint);
+  auto* st =
+      ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                         ast::ImageFormat::kR32Uint, ast::Access::kUndefined);
 
-  Global("a", st, ast::StorageClass::kNone, nullptr,
+  Global("a", st, ast::StorageClass::kNone,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -672,15 +670,15 @@
             "12:34 error: storage textures must have access control");
 }
 
-TEST_F(StorageTextureAccessControlTest, RWAccessControl_Fail) {
+TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
   // [[group(0), binding(0)]]
-  // var a : [[access(readwrite)]] texture_storage_1d<ru32int>;
+  // var a : texture_storage_1d<ru32int, read_write>;
 
-  auto* st = ty.storage_texture(ast::TextureDimension::k1d,
-                                ast::ImageFormat::kR32Uint);
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, st);
+  auto* st =
+      ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                         ast::ImageFormat::kR32Uint, ast::Access::kReadWrite);
 
-  Global(Source{{12, 34}}, "a", ac, ast::StorageClass::kNone, nullptr,
+  Global("a", st, ast::StorageClass::kNone, nullptr,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -692,15 +690,14 @@
             "write-only access");
 }
 
-TEST_F(StorageTextureAccessControlTest, ReadOnlyAccessControl_Pass) {
+TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Pass) {
   // [[group(0), binding(0)]]
-  // var a : [[access(read)]] texture_storage_1d<ru32int>;
+  // var a : texture_storage_1d<ru32int, read>;
 
   auto* st = ty.storage_texture(ast::TextureDimension::k1d,
-                                ast::ImageFormat::kR32Uint);
-  auto* ac = ty.access(ast::AccessControl::kRead, st);
+                                ast::ImageFormat::kR32Uint, ast::Access::kRead);
 
-  Global("a", ac, ast::StorageClass::kNone, nullptr,
+  Global("a", st, ast::StorageClass::kNone, nullptr,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -709,15 +706,15 @@
   EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(StorageTextureAccessControlTest, WriteOnlyAccessControl_Pass) {
+TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
   // [[group(0), binding(0)]]
-  // var a : [[access(write)]] texture_storage_1d<ru32int>;
+  // var a : texture_storage_1d<ru32int, write>;
 
-  auto* st = ty.storage_texture(ast::TextureDimension::k1d,
-                                ast::ImageFormat::kR32Uint);
-  auto* ac = ty.access(ast::AccessControl::kWrite, st);
+  auto* st =
+      ty.storage_texture(ast::TextureDimension::k1d, ast::ImageFormat::kR32Uint,
+                         ast::Access::kWrite);
 
-  Global("a", ac, ast::StorageClass::kNone, nullptr,
+  Global("a", st, ast::StorageClass::kNone, nullptr,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/sem/storage_texture_type.cc b/src/sem/storage_texture_type.cc
index ab6e270..d690354 100644
--- a/src/sem/storage_texture_type.cc
+++ b/src/sem/storage_texture_type.cc
@@ -23,12 +23,9 @@
 
 StorageTexture::StorageTexture(ast::TextureDimension dim,
                                ast::ImageFormat format,
-                               ast::AccessControl::Access access_control,
+                               ast::Access access,
                                sem::Type* subtype)
-    : Base(dim),
-      image_format_(format),
-      access_control_(access_control),
-      subtype_(subtype) {}
+    : Base(dim), image_format_(format), access_(access), subtype_(subtype) {}
 
 StorageTexture::StorageTexture(StorageTexture&&) = default;
 
@@ -37,14 +34,14 @@
 std::string StorageTexture::type_name() const {
   std::ostringstream out;
   out << "__storage_texture_" << dim() << "_" << image_format_ << "_"
-      << access_control_;
+      << access_;
   return out.str();
 }
 
 std::string StorageTexture::FriendlyName(const SymbolTable&) const {
   std::ostringstream out;
-  out << "texture_storage_" << dim() << "<" << image_format_ << ", "
-      << access_control_ << ">";
+  out << "texture_storage_" << dim() << "<" << image_format_ << ", " << access_
+      << ">";
   return out.str();
 }
 
diff --git a/src/sem/storage_texture_type.h b/src/sem/storage_texture_type.h
index 3a36743..216ed28 100644
--- a/src/sem/storage_texture_type.h
+++ b/src/sem/storage_texture_type.h
@@ -17,7 +17,7 @@
 
 #include <string>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/storage_texture.h"
 #include "src/sem/texture_type.h"
 
@@ -32,11 +32,11 @@
   /// Constructor
   /// @param dim the dimensionality of the texture
   /// @param format the image format of the texture
-  /// @param access_control the access control type of the texture
+  /// @param access the access control type of the texture
   /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
   StorageTexture(ast::TextureDimension dim,
                  ast::ImageFormat format,
-                 ast::AccessControl::Access access_control,
+                 ast::Access access,
                  sem::Type* subtype);
 
   /// Move constructor
@@ -50,7 +50,7 @@
   ast::ImageFormat image_format() const { return image_format_; }
 
   /// @returns the access control
-  ast::AccessControl::Access access_control() const { return access_control_; }
+  ast::Access access() const { return access_; }
 
   /// @returns the name for this type
   std::string type_name() const override;
@@ -67,7 +67,7 @@
 
  private:
   ast::ImageFormat const image_format_;
-  ast::AccessControl::Access const access_control_;
+  ast::Access const access_;
   Type* const subtype_;
 };
 
diff --git a/src/sem/storage_texture_type_test.cc b/src/sem/storage_texture_type_test.cc
index 80a078f..8917af0 100644
--- a/src/sem/storage_texture_type_test.cc
+++ b/src/sem/storage_texture_type_test.cc
@@ -30,7 +30,7 @@
       StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
   auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Float,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
   EXPECT_EQ(s->dim(), ast::TextureDimension::k2dArray);
 }
 
@@ -39,7 +39,7 @@
       StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
   auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Float,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
   EXPECT_EQ(s->image_format(), ast::ImageFormat::kRgba32Float);
 }
 
@@ -48,7 +48,7 @@
       StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
   auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Float,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
   EXPECT_EQ(s->type_name(),
             "__storage_texture_2d_array_rgba32float_read_write");
 }
@@ -58,7 +58,7 @@
       StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
   auto* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Float,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
   EXPECT_EQ(s->FriendlyName(Symbols()),
             "texture_storage_2d_array<rgba32float, read_write>");
 }
@@ -68,7 +68,7 @@
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Float, Types());
   Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Float,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
 
   auto program = Build();
 
@@ -83,7 +83,7 @@
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRg32Uint, Types());
   Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRg32Uint,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
 
   auto program = Build();
 
@@ -98,7 +98,7 @@
       sem::StorageTexture::SubtypeFor(ast::ImageFormat::kRgba32Sint, Types());
   Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
                                    ast::ImageFormat::kRgba32Sint,
-                                   ast::AccessControl::kReadWrite, subtype);
+                                   ast::Access::kReadWrite, subtype);
 
   auto program = Build();
 
diff --git a/src/sem/variable.cc b/src/sem/variable.cc
index a8cd011..305b4ac 100644
--- a/src/sem/variable.cc
+++ b/src/sem/variable.cc
@@ -26,11 +26,11 @@
 Variable::Variable(const ast::Variable* declaration,
                    const sem::Type* type,
                    ast::StorageClass storage_class,
-                   ast::AccessControl::Access access_control)
+                   ast::Access access)
     : declaration_(declaration),
       type_(type),
       storage_class_(storage_class),
-      access_control_(access_control),
+      access_(access),
       is_pipeline_constant_(false) {}
 
 Variable::Variable(const ast::Variable* declaration,
@@ -39,7 +39,7 @@
     : declaration_(declaration),
       type_(type),
       storage_class_(ast::StorageClass::kNone),
-      access_control_(ast::AccessControl::kReadWrite),
+      access_(ast::Access::kReadWrite),
       is_pipeline_constant_(true),
       constant_id_(constant_id) {}
 
diff --git a/src/sem/variable.h b/src/sem/variable.h
index 2b2b2e7..ebe9c49 100644
--- a/src/sem/variable.h
+++ b/src/sem/variable.h
@@ -17,7 +17,7 @@
 
 #include <vector>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/storage_class.h"
 #include "src/sem/expression.h"
 
@@ -42,11 +42,11 @@
   /// @param declaration the AST declaration node
   /// @param type the variable type
   /// @param storage_class the variable storage class
-  /// @param access_control the variable access control type
+  /// @param access the variable access control type
   Variable(const ast::Variable* declaration,
            const sem::Type* type,
            ast::StorageClass storage_class,
-           ast::AccessControl::Access access_control);
+           ast::Access access);
 
   /// Constructor for overridable pipeline constants
   /// @param declaration the AST declaration node
@@ -69,7 +69,7 @@
   ast::StorageClass StorageClass() const { return storage_class_; }
 
   /// @returns the access control for the variable
-  ast::AccessControl::Access AccessControl() const { return access_control_; }
+  ast::Access Access() const { return access_; }
 
   /// @returns the expressions that use the variable
   const std::vector<const VariableUser*>& Users() const { return users_; }
@@ -87,7 +87,7 @@
   const ast::Variable* const declaration_;
   const sem::Type* const type_;
   ast::StorageClass const storage_class_;
-  ast::AccessControl::Access const access_control_;
+  ast::Access const access_;
   std::vector<const VariableUser*> users_;
   const bool is_pipeline_constant_;
   const uint16_t constant_id_ = 0;
diff --git a/src/transform/binding_remapper.cc b/src/transform/binding_remapper.cc
index f89bfd9..3755fff 100644
--- a/src/transform/binding_remapper.cc
+++ b/src/transform/binding_remapper.cc
@@ -112,13 +112,12 @@
       // Replace any access controls.
       auto ac_it = remappings->access_controls.find(from);
       if (ac_it != remappings->access_controls.end()) {
-        ast::AccessControl::Access ac = ac_it->second;
+        ast::Access ac = ac_it->second;
         auto* ty = in->Sem().Get(var)->Type()->UnwrapRef();
         ast::Type* inner_ty = CreateASTTypeFor(&ctx, ty);
-        auto* new_ty = ctx.dst->create<ast::AccessControl>(ac, inner_ty);
         auto* new_var = ctx.dst->create<ast::Variable>(
             ctx.Clone(var->source()), ctx.Clone(var->symbol()),
-            var->declared_storage_class(), new_ty, var->is_const(),
+            var->declared_storage_class(), ac, inner_ty, var->is_const(),
             ctx.Clone(var->constructor()), ctx.Clone(var->decorations()));
         ctx.Replace(var, new_var);
       }
diff --git a/src/transform/binding_remapper.h b/src/transform/binding_remapper.h
index 81efa25..b271c1f 100644
--- a/src/transform/binding_remapper.h
+++ b/src/transform/binding_remapper.h
@@ -17,7 +17,7 @@
 
 #include <unordered_map>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/sem/binding_point.h"
 #include "src/transform/transform.h"
 
@@ -35,8 +35,7 @@
   using BindingPoints = std::unordered_map<BindingPoint, BindingPoint>;
 
   /// AccessControls is a map of old binding point to new access control
-  using AccessControls =
-      std::unordered_map<BindingPoint, ast::AccessControl::Access>;
+  using AccessControls = std::unordered_map<BindingPoint, ast::Access>;
 
   /// Remappings is consumed by the BindingRemapper transform.
   /// Data holds information about shader usage and constant buffer offsets.
diff --git a/src/transform/binding_remapper_test.cc b/src/transform/binding_remapper_test.cc
index 2015a01..ed8ce0a 100644
--- a/src/transform/binding_remapper_test.cc
+++ b/src/transform/binding_remapper_test.cc
@@ -30,9 +30,9 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
 [[stage(compute)]]
 fn f() {
@@ -55,9 +55,9 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
 [[stage(compute)]]
 fn f() {
@@ -69,9 +69,9 @@
 struct S {
 };
 
-[[group(1), binding(2)]] var<storage> a : [[access(read)]] S;
+[[group(1), binding(2)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
 [[stage(compute)]]
 fn f() {
@@ -97,11 +97,11 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(write)]] S;
+[[group(3), binding(2)]] var<storage, write> b : S;
 
-[[group(4), binding(3)]] var<storage> c : [[access(read)]] S;
+[[group(4), binding(3)]] var<storage, read> c : S;
 
 [[stage(compute)]]
 fn f() {
@@ -113,11 +113,11 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(write)]] S;
+[[group(2), binding(1)]] var<storage, write> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(write)]] S;
+[[group(3), binding(2)]] var<storage, write> b : S;
 
-[[group(4), binding(3)]] var<storage> c : [[access(read)]] S;
+[[group(4), binding(3)]] var<storage, read> c : S;
 
 [[stage(compute)]]
 fn f() {
@@ -128,9 +128,9 @@
   data.Add<BindingRemapper::Remappings>(
       BindingRemapper::BindingPoints{},
       BindingRemapper::AccessControls{
-          {{2, 1}, ast::AccessControl::kWrite},  // Modify access control
+          {{2, 1}, ast::Access::kWrite},  // Modify access control
           // Keep [[group(3), binding(2)]] as is
-          {{4, 3}, ast::AccessControl::kRead},  // Add access control
+          {{4, 3}, ast::Access::kRead},  // Add access control
       });
   auto got = Run<BindingRemapper>(src, data);
 
@@ -145,9 +145,9 @@
 struct S {
 };
 
-type ReadOnlyS = [[access(read)]] S;
+type, read ReadOnlyS = S;
 
-type WriteOnlyS = [[access(write)]] S;
+type, write WriteOnlyS = S;
 
 type A = S;
 
@@ -167,17 +167,17 @@
 struct S {
 };
 
-type ReadOnlyS = [[access(read)]] S;
+type, read ReadOnlyS = S;
 
-type WriteOnlyS = [[access(write)]] S;
+type, write WriteOnlyS = S;
 
 type A = S;
 
-[[group(2), binding(1)]] var<storage> a : [[access(write)]] S;
+[[group(2), binding(1)]] var<storage, write> a : S;
 
 [[group(3), binding(2)]] var<storage> b : WriteOnlyS;
 
-[[group(4), binding(3)]] var<storage> c : [[access(write)]] S;
+[[group(4), binding(3)]] var<storage, write> c : S;
 
 [[stage(compute)]]
 fn f() {
@@ -188,9 +188,9 @@
   data.Add<BindingRemapper::Remappings>(
       BindingRemapper::BindingPoints{},
       BindingRemapper::AccessControls{
-          {{2, 1}, ast::AccessControl::kWrite},  // Modify access control
+          {{2, 1}, ast::Access::kWrite},  // Modify access control
           // Keep [[group(3), binding(2)]] as is
-          {{4, 3}, ast::AccessControl::kRead},  // Add access control
+          {{4, 3}, ast::Access::kRead},  // Add access control
       });
   auto got = Run<BindingRemapper>(src, data);
 
@@ -203,9 +203,9 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
 [[stage(compute)]]
 fn f() {
@@ -217,9 +217,9 @@
 struct S {
 };
 
-[[group(4), binding(5)]] var<storage> a : [[access(write)]] S;
+[[group(4), binding(5)]] var<storage, write> a : S;
 
-[[group(6), binding(7)]] var<storage> b : [[access(write)]] S;
+[[group(6), binding(7)]] var<storage, write> b : S;
 
 [[stage(compute)]]
 fn f() {
@@ -233,8 +233,8 @@
           {{3, 2}, {6, 7}},
       },
       BindingRemapper::AccessControls{
-          {{2, 1}, ast::AccessControl::kWrite},
-          {{3, 2}, ast::AccessControl::kWrite},
+          {{2, 1}, ast::Access::kWrite},
+          {{3, 2}, ast::Access::kWrite},
       });
   auto got = Run<BindingRemapper>(src, data);
 
@@ -248,13 +248,13 @@
   i : i32;
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
-[[group(4), binding(3)]] var<storage> c : [[access(read)]] S;
+[[group(4), binding(3)]] var<storage, read> c : S;
 
-[[group(5), binding(4)]] var<storage> d : [[access(read)]] S;
+[[group(5), binding(4)]] var<storage, read> d : S;
 
 [[stage(compute)]]
 fn f() {
@@ -268,13 +268,13 @@
   i : i32;
 };
 
-[[internal(disable_validation__binding_point_collision), group(1), binding(1)]] var<storage> a : [[access(read)]] S;
+[[internal(disable_validation__binding_point_collision), group(1), binding(1)]] var<storage, read> a : S;
 
-[[internal(disable_validation__binding_point_collision), group(1), binding(1)]] var<storage> b : [[access(read)]] S;
+[[internal(disable_validation__binding_point_collision), group(1), binding(1)]] var<storage, read> b : S;
 
-[[internal(disable_validation__binding_point_collision), group(5), binding(4)]] var<storage> c : [[access(read)]] S;
+[[internal(disable_validation__binding_point_collision), group(5), binding(4)]] var<storage, read> c : S;
 
-[[internal(disable_validation__binding_point_collision), group(5), binding(4)]] var<storage> d : [[access(read)]] S;
+[[internal(disable_validation__binding_point_collision), group(5), binding(4)]] var<storage, read> d : S;
 
 [[stage(compute)]]
 fn f() {
@@ -302,13 +302,13 @@
   i : i32;
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
 
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
-[[group(4), binding(3)]] var<storage> c : [[access(read)]] S;
+[[group(4), binding(3)]] var<storage, read> c : S;
 
-[[group(5), binding(4)]] var<storage> d : [[access(read)]] S;
+[[group(5), binding(4)]] var<storage, read> d : S;
 
 [[stage(compute)]]
 fn f1() {
@@ -327,13 +327,13 @@
   i : i32;
 };
 
-[[group(1), binding(1)]] var<storage> a : [[access(read)]] S;
+[[group(1), binding(1)]] var<storage, read> a : S;
 
-[[group(1), binding(1)]] var<storage> b : [[access(read)]] S;
+[[group(1), binding(1)]] var<storage, read> b : S;
 
-[[group(5), binding(4)]] var<storage> c : [[access(read)]] S;
+[[group(5), binding(4)]] var<storage, read> c : S;
 
-[[group(5), binding(4)]] var<storage> d : [[access(read)]] S;
+[[group(5), binding(4)]] var<storage, read> d : S;
 
 [[stage(compute)]]
 fn f1() {
@@ -365,8 +365,8 @@
 struct S {
 };
 
-[[group(2), binding(1)]] var<storage> a : [[access(read)]] S;
-[[group(3), binding(2)]] var<storage> b : [[access(read)]] S;
+[[group(2), binding(1)]] var<storage, read> a : S;
+[[group(3), binding(2)]] var<storage, read> b : S;
 
 [[stage(compute)]]
 fn f() {}
diff --git a/src/transform/bound_array_accessors_test.cc b/src/transform/bound_array_accessors_test.cc
index b9120d4..53e15d3 100644
--- a/src/transform/bound_array_accessors_test.cc
+++ b/src/transform/bound_array_accessors_test.cc
@@ -540,7 +540,7 @@
   a : f32;
   b : array<f32>;
 };
-[[group(0), binding(0)]] var<storage> s : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> s : S;
 
 fn f() {
   var d : f32 = s.b[25];
@@ -554,7 +554,7 @@
   b : array<f32>;
 };
 
-[[group(0), binding(0)]] var<storage> s : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> s : S;
 
 fn f() {
   var d : f32 = s.b[min(u32(25), (arrayLength(s.b) - 1u))];
@@ -601,7 +601,7 @@
   b : array<f32>;
 };
 
-[[group(0), binding(0)]] var<storage> s : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> s : S;
 
 let c : u32 = 1u;
 
@@ -619,7 +619,7 @@
   b : array<f32>;
 };
 
-[[group(0), binding(0)]] var<storage> s : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> s : S;
 
 let c : u32 = 1u;
 
diff --git a/src/transform/calculate_array_length.cc b/src/transform/calculate_array_length.cc
index e6becb4..19490df 100644
--- a/src/transform/calculate_array_length.cc
+++ b/src/transform/calculate_array_length.cc
@@ -91,7 +91,8 @@
               // in order for HLSL to emit this as a ByteAddressBuffer.
               ctx.dst->create<ast::Variable>(
                   ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
-                  buffer_typename, true, nullptr, ast::DecorationList{}),
+                  ast::Access::kUndefined, buffer_typename, true, nullptr,
+                  ast::DecorationList{}),
               ctx.dst->Param("result",
                              ctx.dst->ty.pointer(ctx.dst->ty.u32(),
                                                  ast::StorageClass::kFunction)),
diff --git a/src/transform/calculate_array_length_test.cc b/src/transform/calculate_array_length_test.cc
index 30083c3..557454b 100644
--- a/src/transform/calculate_array_length_test.cc
+++ b/src/transform/calculate_array_length_test.cc
@@ -30,7 +30,7 @@
   arr : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -48,7 +48,7 @@
 [[internal(intrinsic_buffer_size)]]
 fn tint_symbol(buffer : SB, result : ptr<function, u32>)
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -72,7 +72,7 @@
   arr : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -92,7 +92,7 @@
 [[internal(intrinsic_buffer_size)]]
 fn tint_symbol(buffer : SB, result : ptr<function, u32>)
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -119,7 +119,7 @@
   arr : [[stride(64)]] array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -138,7 +138,7 @@
 [[internal(intrinsic_buffer_size)]]
 fn tint_symbol(buffer : SB, result : ptr<function, u32>)
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -162,7 +162,7 @@
   arr : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -186,7 +186,7 @@
 [[internal(intrinsic_buffer_size)]]
 fn tint_symbol(buffer : SB, result : ptr<function, u32>)
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -225,9 +225,9 @@
   arr2 : array<vec4<f32>>;
 };
 
-[[group(0), binding(0)]] var<storage> sb1 : [[access(read)]] SB1;
+[[group(0), binding(0)]] var<storage, read> sb1 : SB1;
 
-[[group(0), binding(1)]] var<storage> sb2 : [[access(read)]] SB2;
+[[group(0), binding(1)]] var<storage, read> sb2 : SB2;
 
 [[stage(compute)]]
 fn main() {
@@ -256,9 +256,9 @@
 [[internal(intrinsic_buffer_size)]]
 fn tint_symbol_3(buffer : SB2, result : ptr<function, u32>)
 
-[[group(0), binding(0)]] var<storage> sb1 : [[access(read)]] SB1;
+[[group(0), binding(0)]] var<storage, read> sb1 : SB1;
 
-[[group(0), binding(1)]] var<storage> sb2 : [[access(read)]] SB2;
+[[group(0), binding(1)]] var<storage, read> sb2 : SB2;
 
 [[stage(compute)]]
 fn main() {
diff --git a/src/transform/decompose_storage_access.cc b/src/transform/decompose_storage_access.cc
index e718b13..c89288c 100644
--- a/src/transform/decompose_storage_access.cc
+++ b/src/transform/decompose_storage_access.cc
@@ -360,17 +360,6 @@
   StorageBufferAccess target;            // The target for the write
 };
 
-ast::Type* MaybeCreateASTAccessControl(CloneContext* ctx,
-                                       const sem::VariableUser* var_user,
-                                       ast::Type* ty) {
-  if (var_user &&
-      var_user->Variable()->StorageClass() == ast::StorageClass::kStorage) {
-    return ctx->dst->create<ast::AccessControl>(
-        var_user->Variable()->AccessControl(), ty);
-  }
-  return ty;
-}
-
 }  // namespace
 
 /// State holds the current transform state
@@ -431,14 +420,14 @@
                   const sem::VariableUser* var_user) {
     return utils::GetOrCreate(load_funcs, TypePair{buf_ty, el_ty}, [&] {
       auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
-      buf_ast_ty = MaybeCreateASTAccessControl(&ctx, var_user, buf_ast_ty);
 
       ast::VariableList params = {
           // Note: The buffer parameter requires the kStorage StorageClass in
           // order for HLSL to emit this as a ByteAddressBuffer.
           ctx.dst->create<ast::Variable>(
-              ctx.dst->Sym("buffer"), ast::StorageClass::kStorage, buf_ast_ty,
-              true, nullptr, ast::DecorationList{}),
+              ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
+              var_user->Variable()->Access(), buf_ast_ty, true, nullptr,
+              ast::DecorationList{}),
           ctx.dst->Param("offset", ctx.dst->ty.u32()),
       };
 
@@ -507,14 +496,14 @@
                    const sem::VariableUser* var_user) {
     return utils::GetOrCreate(store_funcs, TypePair{buf_ty, el_ty}, [&] {
       auto* buf_ast_ty = CreateASTTypeFor(&ctx, buf_ty);
-      buf_ast_ty = MaybeCreateASTAccessControl(&ctx, var_user, buf_ast_ty);
       auto* el_ast_ty = CreateASTTypeFor(&ctx, el_ty);
       ast::VariableList params{
           // Note: The buffer parameter requires the kStorage StorageClass in
           // order for HLSL to emit this as a ByteAddressBuffer.
           ctx.dst->create<ast::Variable>(
-              ctx.dst->Sym("buffer"), ast::StorageClass::kStorage, buf_ast_ty,
-              true, nullptr, ast::DecorationList{}),
+              ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
+              var_user->Variable()->Access(), buf_ast_ty, true, nullptr,
+              ast::DecorationList{}),
           ctx.dst->Param("offset", ctx.dst->ty.u32()),
           ctx.dst->Param("value", el_ast_ty),
       };
diff --git a/src/transform/decompose_storage_access_test.cc b/src/transform/decompose_storage_access_test.cc
index 62fa75c..5d870f9 100644
--- a/src/transform/decompose_storage_access_test.cc
+++ b/src/transform/decompose_storage_access_test.cc
@@ -50,7 +50,7 @@
   v : array<vec3<f32>, 2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -107,82 +107,82 @@
 };
 
 [[internal(intrinsic_load_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32) -> i32
+fn tint_symbol(buffer : SB, offset : u32) -> i32
 
 [[internal(intrinsic_load_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_1(buffer : [[access(read_write)]] SB, offset : u32) -> u32
+fn tint_symbol_1(buffer : SB, offset : u32) -> u32
 
 [[internal(intrinsic_load_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_2(buffer : [[access(read_write)]] SB, offset : u32) -> f32
+fn tint_symbol_2(buffer : SB, offset : u32) -> f32
 
 [[internal(intrinsic_load_vec2_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_3(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(buffer : SB, offset : u32) -> vec2<i32>
 
 [[internal(intrinsic_load_vec2_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_4(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(buffer : SB, offset : u32) -> vec2<u32>
 
 [[internal(intrinsic_load_vec2_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_5(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(buffer : SB, offset : u32) -> vec2<f32>
 
 [[internal(intrinsic_load_vec3_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_6(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(buffer : SB, offset : u32) -> vec3<i32>
 
 [[internal(intrinsic_load_vec3_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_7(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(buffer : SB, offset : u32) -> vec3<u32>
 
 [[internal(intrinsic_load_vec3_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_8(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(buffer : SB, offset : u32) -> vec3<f32>
 
 [[internal(intrinsic_load_vec4_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_9(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(buffer : SB, offset : u32) -> vec4<i32>
 
 [[internal(intrinsic_load_vec4_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_10(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(buffer : SB, offset : u32) -> vec4<u32>
 
 [[internal(intrinsic_load_vec4_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_11(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(buffer : SB, offset : u32) -> vec4<f32>
 
-fn tint_symbol_12(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(buffer : SB, offset : u32) -> mat2x2<f32> {
   return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
 }
 
-fn tint_symbol_13(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(buffer : SB, offset : u32) -> mat2x3<f32> {
   return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_14(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(buffer : SB, offset : u32) -> mat2x4<f32> {
   return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_15(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(buffer : SB, offset : u32) -> mat3x2<f32> {
   return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_16(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(buffer : SB, offset : u32) -> mat3x3<f32> {
   return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
 }
 
-fn tint_symbol_17(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(buffer : SB, offset : u32) -> mat3x4<f32> {
   return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
 }
 
-fn tint_symbol_18(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(buffer : SB, offset : u32) -> mat4x2<f32> {
   return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
 }
 
-fn tint_symbol_19(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(buffer : SB, offset : u32) -> mat4x3<f32> {
   return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
 }
 
-fn tint_symbol_20(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(buffer : SB, offset : u32) -> mat4x4<f32> {
   return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
 }
 
-fn tint_symbol_21(buffer : [[access(read_write)]] SB, offset : u32) -> array<vec3<f32>, 2> {
+fn tint_symbol_21(buffer : SB, offset : u32) -> array<vec3<f32>, 2> {
   return array<vec3<f32>, 2>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
 }
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -244,7 +244,7 @@
   v : array<vec3<f32>, 2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -301,101 +301,101 @@
 };
 
 [[internal(intrinsic_store_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32, value : i32)
+fn tint_symbol(buffer : SB, offset : u32, value : i32)
 
 [[internal(intrinsic_store_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_1(buffer : [[access(read_write)]] SB, offset : u32, value : u32)
+fn tint_symbol_1(buffer : SB, offset : u32, value : u32)
 
 [[internal(intrinsic_store_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_2(buffer : [[access(read_write)]] SB, offset : u32, value : f32)
+fn tint_symbol_2(buffer : SB, offset : u32, value : f32)
 
 [[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_3(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_3(buffer : SB, offset : u32, value : vec2<i32>)
 
 [[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_4(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_4(buffer : SB, offset : u32, value : vec2<u32>)
 
 [[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_5(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_5(buffer : SB, offset : u32, value : vec2<f32>)
 
 [[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_6(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_6(buffer : SB, offset : u32, value : vec3<i32>)
 
 [[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_7(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_7(buffer : SB, offset : u32, value : vec3<u32>)
 
 [[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_8(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_8(buffer : SB, offset : u32, value : vec3<f32>)
 
 [[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_9(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_9(buffer : SB, offset : u32, value : vec4<i32>)
 
 [[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_10(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_10(buffer : SB, offset : u32, value : vec4<u32>)
 
 [[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_11(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_11(buffer : SB, offset : u32, value : vec4<f32>)
 
-fn tint_symbol_12(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_12(buffer : SB, offset : u32, value : mat2x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
 }
 
-fn tint_symbol_13(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_13(buffer : SB, offset : u32, value : mat2x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
 }
 
-fn tint_symbol_14(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_14(buffer : SB, offset : u32, value : mat2x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
 }
 
-fn tint_symbol_15(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_15(buffer : SB, offset : u32, value : mat3x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
   tint_symbol_5(buffer, (offset + 16u), value[2u]);
 }
 
-fn tint_symbol_16(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_16(buffer : SB, offset : u32, value : mat3x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
   tint_symbol_8(buffer, (offset + 32u), value[2u]);
 }
 
-fn tint_symbol_17(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_17(buffer : SB, offset : u32, value : mat3x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
   tint_symbol_11(buffer, (offset + 32u), value[2u]);
 }
 
-fn tint_symbol_18(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_18(buffer : SB, offset : u32, value : mat4x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
   tint_symbol_5(buffer, (offset + 16u), value[2u]);
   tint_symbol_5(buffer, (offset + 24u), value[3u]);
 }
 
-fn tint_symbol_19(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_19(buffer : SB, offset : u32, value : mat4x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
   tint_symbol_8(buffer, (offset + 32u), value[2u]);
   tint_symbol_8(buffer, (offset + 48u), value[3u]);
 }
 
-fn tint_symbol_20(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_20(buffer : SB, offset : u32, value : mat4x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
   tint_symbol_11(buffer, (offset + 32u), value[2u]);
   tint_symbol_11(buffer, (offset + 48u), value[3u]);
 }
 
-fn tint_symbol_21(buffer : [[access(read_write)]] SB, offset : u32, value : array<vec3<f32>, 2>) {
+fn tint_symbol_21(buffer : SB, offset : u32, value : array<vec3<f32>, 2>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
 }
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -457,7 +457,7 @@
   v : array<vec3<f32>, 2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -493,86 +493,86 @@
 };
 
 [[internal(intrinsic_load_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32) -> i32
+fn tint_symbol(buffer : SB, offset : u32) -> i32
 
 [[internal(intrinsic_load_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_1(buffer : [[access(read_write)]] SB, offset : u32) -> u32
+fn tint_symbol_1(buffer : SB, offset : u32) -> u32
 
 [[internal(intrinsic_load_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_2(buffer : [[access(read_write)]] SB, offset : u32) -> f32
+fn tint_symbol_2(buffer : SB, offset : u32) -> f32
 
 [[internal(intrinsic_load_vec2_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_3(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<i32>
+fn tint_symbol_3(buffer : SB, offset : u32) -> vec2<i32>
 
 [[internal(intrinsic_load_vec2_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_4(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<u32>
+fn tint_symbol_4(buffer : SB, offset : u32) -> vec2<u32>
 
 [[internal(intrinsic_load_vec2_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_5(buffer : [[access(read_write)]] SB, offset : u32) -> vec2<f32>
+fn tint_symbol_5(buffer : SB, offset : u32) -> vec2<f32>
 
 [[internal(intrinsic_load_vec3_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_6(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<i32>
+fn tint_symbol_6(buffer : SB, offset : u32) -> vec3<i32>
 
 [[internal(intrinsic_load_vec3_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_7(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<u32>
+fn tint_symbol_7(buffer : SB, offset : u32) -> vec3<u32>
 
 [[internal(intrinsic_load_vec3_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_8(buffer : [[access(read_write)]] SB, offset : u32) -> vec3<f32>
+fn tint_symbol_8(buffer : SB, offset : u32) -> vec3<f32>
 
 [[internal(intrinsic_load_vec4_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_9(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<i32>
+fn tint_symbol_9(buffer : SB, offset : u32) -> vec4<i32>
 
 [[internal(intrinsic_load_vec4_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_10(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<u32>
+fn tint_symbol_10(buffer : SB, offset : u32) -> vec4<u32>
 
 [[internal(intrinsic_load_vec4_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_11(buffer : [[access(read_write)]] SB, offset : u32) -> vec4<f32>
+fn tint_symbol_11(buffer : SB, offset : u32) -> vec4<f32>
 
-fn tint_symbol_12(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x2<f32> {
+fn tint_symbol_12(buffer : SB, offset : u32) -> mat2x2<f32> {
   return mat2x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)));
 }
 
-fn tint_symbol_13(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x3<f32> {
+fn tint_symbol_13(buffer : SB, offset : u32) -> mat2x3<f32> {
   return mat2x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_14(buffer : [[access(read_write)]] SB, offset : u32) -> mat2x4<f32> {
+fn tint_symbol_14(buffer : SB, offset : u32) -> mat2x4<f32> {
   return mat2x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_15(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x2<f32> {
+fn tint_symbol_15(buffer : SB, offset : u32) -> mat3x2<f32> {
   return mat3x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_16(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x3<f32> {
+fn tint_symbol_16(buffer : SB, offset : u32) -> mat3x3<f32> {
   return mat3x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)));
 }
 
-fn tint_symbol_17(buffer : [[access(read_write)]] SB, offset : u32) -> mat3x4<f32> {
+fn tint_symbol_17(buffer : SB, offset : u32) -> mat3x4<f32> {
   return mat3x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)));
 }
 
-fn tint_symbol_18(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x2<f32> {
+fn tint_symbol_18(buffer : SB, offset : u32) -> mat4x2<f32> {
   return mat4x2<f32>(tint_symbol_5(buffer, (offset + 0u)), tint_symbol_5(buffer, (offset + 8u)), tint_symbol_5(buffer, (offset + 16u)), tint_symbol_5(buffer, (offset + 24u)));
 }
 
-fn tint_symbol_19(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x3<f32> {
+fn tint_symbol_19(buffer : SB, offset : u32) -> mat4x3<f32> {
   return mat4x3<f32>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)), tint_symbol_8(buffer, (offset + 32u)), tint_symbol_8(buffer, (offset + 48u)));
 }
 
-fn tint_symbol_20(buffer : [[access(read_write)]] SB, offset : u32) -> mat4x4<f32> {
+fn tint_symbol_20(buffer : SB, offset : u32) -> mat4x4<f32> {
   return mat4x4<f32>(tint_symbol_11(buffer, (offset + 0u)), tint_symbol_11(buffer, (offset + 16u)), tint_symbol_11(buffer, (offset + 32u)), tint_symbol_11(buffer, (offset + 48u)));
 }
 
-fn tint_symbol_21(buffer : [[access(read_write)]] SB, offset : u32) -> array<vec3<f32>, 2> {
+fn tint_symbol_21(buffer : SB, offset : u32) -> array<vec3<f32>, 2> {
   return array<vec3<f32>, 2>(tint_symbol_8(buffer, (offset + 0u)), tint_symbol_8(buffer, (offset + 16u)));
 }
 
-fn tint_symbol_22(buffer : [[access(read_write)]] SB, offset : u32) -> SB {
+fn tint_symbol_22(buffer : SB, offset : u32) -> SB {
   return SB(tint_symbol(buffer, (offset + 0u)), tint_symbol_1(buffer, (offset + 4u)), tint_symbol_2(buffer, (offset + 8u)), tint_symbol_3(buffer, (offset + 16u)), tint_symbol_4(buffer, (offset + 24u)), tint_symbol_5(buffer, (offset + 32u)), tint_symbol_6(buffer, (offset + 48u)), tint_symbol_7(buffer, (offset + 64u)), tint_symbol_8(buffer, (offset + 80u)), tint_symbol_9(buffer, (offset + 96u)), tint_symbol_10(buffer, (offset + 112u)), tint_symbol_11(buffer, (offset + 128u)), tint_symbol_12(buffer, (offset + 144u)), tint_symbol_13(buffer, (offset + 160u)), tint_symbol_14(buffer, (offset + 192u)), tint_symbol_15(buffer, (offset + 224u)), tint_symbol_16(buffer, (offset + 256u)), tint_symbol_17(buffer, (offset + 304u)), tint_symbol_18(buffer, (offset + 352u)), tint_symbol_19(buffer, (offset + 384u)), tint_symbol_20(buffer, (offset + 448u)), tint_symbol_21(buffer, (offset + 512u)));
 }
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -613,7 +613,7 @@
   v : array<vec3<f32>, 2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -649,101 +649,101 @@
 };
 
 [[internal(intrinsic_store_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32, value : i32)
+fn tint_symbol(buffer : SB, offset : u32, value : i32)
 
 [[internal(intrinsic_store_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_1(buffer : [[access(read_write)]] SB, offset : u32, value : u32)
+fn tint_symbol_1(buffer : SB, offset : u32, value : u32)
 
 [[internal(intrinsic_store_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_2(buffer : [[access(read_write)]] SB, offset : u32, value : f32)
+fn tint_symbol_2(buffer : SB, offset : u32, value : f32)
 
 [[internal(intrinsic_store_vec2_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_3(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<i32>)
+fn tint_symbol_3(buffer : SB, offset : u32, value : vec2<i32>)
 
 [[internal(intrinsic_store_vec2_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_4(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<u32>)
+fn tint_symbol_4(buffer : SB, offset : u32, value : vec2<u32>)
 
 [[internal(intrinsic_store_vec2_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_5(buffer : [[access(read_write)]] SB, offset : u32, value : vec2<f32>)
+fn tint_symbol_5(buffer : SB, offset : u32, value : vec2<f32>)
 
 [[internal(intrinsic_store_vec3_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_6(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<i32>)
+fn tint_symbol_6(buffer : SB, offset : u32, value : vec3<i32>)
 
 [[internal(intrinsic_store_vec3_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_7(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<u32>)
+fn tint_symbol_7(buffer : SB, offset : u32, value : vec3<u32>)
 
 [[internal(intrinsic_store_vec3_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_8(buffer : [[access(read_write)]] SB, offset : u32, value : vec3<f32>)
+fn tint_symbol_8(buffer : SB, offset : u32, value : vec3<f32>)
 
 [[internal(intrinsic_store_vec4_u32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_9(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<i32>)
+fn tint_symbol_9(buffer : SB, offset : u32, value : vec4<i32>)
 
 [[internal(intrinsic_store_vec4_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_10(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<u32>)
+fn tint_symbol_10(buffer : SB, offset : u32, value : vec4<u32>)
 
 [[internal(intrinsic_store_vec4_i32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol_11(buffer : [[access(read_write)]] SB, offset : u32, value : vec4<f32>)
+fn tint_symbol_11(buffer : SB, offset : u32, value : vec4<f32>)
 
-fn tint_symbol_12(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x2<f32>) {
+fn tint_symbol_12(buffer : SB, offset : u32, value : mat2x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
 }
 
-fn tint_symbol_13(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x3<f32>) {
+fn tint_symbol_13(buffer : SB, offset : u32, value : mat2x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
 }
 
-fn tint_symbol_14(buffer : [[access(read_write)]] SB, offset : u32, value : mat2x4<f32>) {
+fn tint_symbol_14(buffer : SB, offset : u32, value : mat2x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
 }
 
-fn tint_symbol_15(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x2<f32>) {
+fn tint_symbol_15(buffer : SB, offset : u32, value : mat3x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
   tint_symbol_5(buffer, (offset + 16u), value[2u]);
 }
 
-fn tint_symbol_16(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x3<f32>) {
+fn tint_symbol_16(buffer : SB, offset : u32, value : mat3x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
   tint_symbol_8(buffer, (offset + 32u), value[2u]);
 }
 
-fn tint_symbol_17(buffer : [[access(read_write)]] SB, offset : u32, value : mat3x4<f32>) {
+fn tint_symbol_17(buffer : SB, offset : u32, value : mat3x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
   tint_symbol_11(buffer, (offset + 32u), value[2u]);
 }
 
-fn tint_symbol_18(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x2<f32>) {
+fn tint_symbol_18(buffer : SB, offset : u32, value : mat4x2<f32>) {
   tint_symbol_5(buffer, (offset + 0u), value[0u]);
   tint_symbol_5(buffer, (offset + 8u), value[1u]);
   tint_symbol_5(buffer, (offset + 16u), value[2u]);
   tint_symbol_5(buffer, (offset + 24u), value[3u]);
 }
 
-fn tint_symbol_19(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x3<f32>) {
+fn tint_symbol_19(buffer : SB, offset : u32, value : mat4x3<f32>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
   tint_symbol_8(buffer, (offset + 32u), value[2u]);
   tint_symbol_8(buffer, (offset + 48u), value[3u]);
 }
 
-fn tint_symbol_20(buffer : [[access(read_write)]] SB, offset : u32, value : mat4x4<f32>) {
+fn tint_symbol_20(buffer : SB, offset : u32, value : mat4x4<f32>) {
   tint_symbol_11(buffer, (offset + 0u), value[0u]);
   tint_symbol_11(buffer, (offset + 16u), value[1u]);
   tint_symbol_11(buffer, (offset + 32u), value[2u]);
   tint_symbol_11(buffer, (offset + 48u), value[3u]);
 }
 
-fn tint_symbol_21(buffer : [[access(read_write)]] SB, offset : u32, value : array<vec3<f32>, 2>) {
+fn tint_symbol_21(buffer : SB, offset : u32, value : array<vec3<f32>, 2>) {
   tint_symbol_8(buffer, (offset + 0u), value[0u]);
   tint_symbol_8(buffer, (offset + 16u), value[1u]);
 }
 
-fn tint_symbol_22(buffer : [[access(read_write)]] SB, offset : u32, value : SB) {
+fn tint_symbol_22(buffer : SB, offset : u32, value : SB) {
   tint_symbol(buffer, (offset + 0u), value.a);
   tint_symbol_1(buffer, (offset + 4u), value.b);
   tint_symbol_2(buffer, (offset + 8u), value.c);
@@ -768,7 +768,7 @@
   tint_symbol_21(buffer, (offset + 512u), value.v);
 }
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -802,7 +802,7 @@
   b : [[stride(256)]] array<S2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -838,9 +838,9 @@
 };
 
 [[internal(intrinsic_load_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32) -> f32
+fn tint_symbol(buffer : SB, offset : u32) -> f32
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -874,7 +874,7 @@
   b : [[stride(256)]] array<S2>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -906,9 +906,9 @@
 };
 
 [[internal(intrinsic_load_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32) -> f32
+fn tint_symbol(buffer : SB, offset : u32) -> f32
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -953,7 +953,7 @@
   b : A2_Array;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
@@ -993,9 +993,9 @@
 };
 
 [[internal(intrinsic_load_f32), internal(disable_validation__function_has_no_body)]]
-fn tint_symbol(buffer : [[access(read_write)]] SB, offset : u32) -> f32
+fn tint_symbol(buffer : SB, offset : u32) -> f32
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
 
 [[stage(compute)]]
 fn main() {
diff --git a/src/transform/external_texture_transform.cc b/src/transform/external_texture_transform.cc
index 036c296..81e4fab 100644
--- a/src/transform/external_texture_transform.cc
+++ b/src/transform/external_texture_transform.cc
@@ -115,8 +115,9 @@
         auto* clonedConstructor = ctx.Clone(var->constructor());
         auto clonedDecorations = ctx.Clone(var->decorations());
         auto* newVar = ctx.dst->create<ast::Variable>(
-            clonedSrc, clonedSym, var->declared_storage_class(), newType,
-            var->is_const(), clonedConstructor, clonedDecorations);
+            clonedSrc, clonedSym, var->declared_storage_class(),
+            var->declared_access(), newType, var->is_const(), clonedConstructor,
+            clonedDecorations);
 
         ctx.Replace(var, newVar);
       }
diff --git a/src/transform/vertex_pulling.cc b/src/transform/vertex_pulling.cc
index 296e2d8..9f3b3bf 100644
--- a/src/transform/vertex_pulling.cc
+++ b/src/transform/vertex_pulling.cc
@@ -214,10 +214,10 @@
             ctx.dst->create<ast::StructBlockDecoration>(),
         });
     for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
-      auto* access = ctx.dst->ty.access(ast::AccessControl::kRead, struct_type);
       // The decorated variable with struct type
       ctx.dst->Global(
-          GetVertexBufferName(i), access, ast::StorageClass::kStorage, nullptr,
+          GetVertexBufferName(i), struct_type, ast::StorageClass::kStorage,
+          ast::Access::kRead,
           ast::DecorationList{
               ctx.dst->create<ast::BindingDecoration>(i),
               ctx.dst->create<ast::GroupDecoration>(cfg.pulling_group),
diff --git a/src/transform/vertex_pulling_test.cc b/src/transform/vertex_pulling_test.cc
index 1e6ff9e..04e5f6a 100644
--- a/src/transform/vertex_pulling_test.cc
+++ b/src/transform/vertex_pulling_test.cc
@@ -121,7 +121,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] tint_pulling_vertex_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -161,7 +161,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(instance_index)]] tint_pulling_instance_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -201,7 +201,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(5)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(5)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] tint_pulling_vertex_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -246,7 +246,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 struct Inputs {
   [[location(0)]]
@@ -296,9 +296,9 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
-[[binding(1), group(4)]] var<storage> tint_pulling_vertex_buffer_1 : [[access(read)]] TintVertexData;
+[[binding(1), group(4)]] var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] custom_vertex_index : u32, [[builtin(instance_index)]] custom_instance_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -358,9 +358,9 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
-[[binding(1), group(4)]] var<storage> tint_pulling_vertex_buffer_1 : [[access(read)]] TintVertexData;
+[[binding(1), group(4)]] var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
 
 struct tint_symbol {
   [[builtin(vertex_index)]]
@@ -442,9 +442,9 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
-[[binding(1), group(4)]] var<storage> tint_pulling_vertex_buffer_1 : [[access(read)]] TintVertexData;
+[[binding(1), group(4)]] var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
 
 struct Inputs {
   [[location(0)]]
@@ -511,7 +511,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] tint_pulling_vertex_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -559,11 +559,11 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
-[[binding(1), group(4)]] var<storage> tint_pulling_vertex_buffer_1 : [[access(read)]] TintVertexData;
+[[binding(1), group(4)]] var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
 
-[[binding(2), group(4)]] var<storage> tint_pulling_vertex_buffer_2 : [[access(read)]] TintVertexData;
+[[binding(2), group(4)]] var<storage, read> tint_pulling_vertex_buffer_2 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] tint_pulling_vertex_index : u32) -> [[builtin(position)]] vec4<f32> {
@@ -617,7 +617,7 @@
   tint_vertex_data_1 : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0_1 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0_1 : TintVertexData;
 
 [[stage(vertex)]]
 fn main([[builtin(vertex_index)]] tint_pulling_vertex_index_1 : u32) -> [[builtin(position)]] vec4<f32> {
@@ -671,7 +671,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(5)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(5)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 var<private> var_a : f32;
 
@@ -720,9 +720,9 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
-[[binding(1), group(4)]] var<storage> tint_pulling_vertex_buffer_1 : [[access(read)]] TintVertexData;
+[[binding(1), group(4)]] var<storage, read> tint_pulling_vertex_buffer_1 : TintVertexData;
 
 var<private> var_a : f32;
 
@@ -787,7 +787,7 @@
   tint_vertex_data : [[stride(4)]] array<u32>;
 };
 
-[[binding(0), group(4)]] var<storage> tint_pulling_vertex_buffer_0 : [[access(read)]] TintVertexData;
+[[binding(0), group(4)]] var<storage, read> tint_pulling_vertex_buffer_0 : TintVertexData;
 
 var<private> var_a : f32;
 
diff --git a/src/writer/hlsl/generator_impl.cc b/src/writer/hlsl/generator_impl.cc
index d25dc88..394017d 100644
--- a/src/writer/hlsl/generator_impl.cc
+++ b/src/writer/hlsl/generator_impl.cc
@@ -248,8 +248,8 @@
   }
 
   out << "as";
-  if (!EmitType(out, type, ast::StorageClass::kNone,
-                ast::AccessControl::kReadWrite, "")) {
+  if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
+                "")) {
     return false;
   }
   out << "(";
@@ -1303,8 +1303,8 @@
   if (brackets) {
     out << "{";
   } else {
-    if (!EmitType(out, type, ast::StorageClass::kNone,
-                  ast::AccessControl::kReadWrite, "")) {
+    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
+                  "")) {
       return false;
     }
     out << "(";
@@ -1566,7 +1566,7 @@
   auto* func = builder_.Sem().Get(func_ast);
 
   if (!EmitType(out, func->ReturnType(), ast::StorageClass::kNone,
-                ast::AccessControl::kReadWrite, "")) {
+                ast::Access::kReadWrite, "")) {
     return false;
   }
 
@@ -1633,7 +1633,7 @@
     // buffers. These functions have a storage buffer parameter with
     // StorageClass::kStorage. This is required to correctly translate the
     // parameter to [RW]ByteAddressBuffer.
-    if (!EmitType(out, type, v->StorageClass(), v->AccessControl(),
+    if (!EmitType(out, type, v->StorageClass(), v->Access(),
                   builder_.Symbols().NameFor(v->Declaration()->symbol()))) {
       return false;
     }
@@ -1720,7 +1720,7 @@
 
       increment_indent();
       make_indent(out);
-      if (!EmitType(out, type, var->StorageClass(), var->AccessControl(), "")) {
+      if (!EmitType(out, type, var->StorageClass(), var->Access(), "")) {
         return false;
       }
       out << " " << builder_.Symbols().NameFor(decl->symbol()) << ";"
@@ -1746,15 +1746,13 @@
     }
 
     auto* type = var->Type()->UnwrapRef();
-    if (!EmitType(out, type, ast::StorageClass::kStorage, var->AccessControl(),
-                  "")) {
+    if (!EmitType(out, type, ast::StorageClass::kStorage, var->Access(), "")) {
       return false;
     }
 
     out << " " << builder_.Symbols().NameFor(decl->symbol())
-        << RegisterAndSpace(
-               var->AccessControl() == ast::AccessControl::kRead ? 't' : 'u',
-               binding_point)
+        << RegisterAndSpace(var->Access() == ast::Access::kRead ? 't' : 'u',
+                            binding_point)
         << ";" << std::endl;
     emitted_storagebuffer = true;
   }
@@ -1781,7 +1779,7 @@
       auto* type = sem->Type()->UnwrapRef();
 
       make_indent(out);
-      if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
+      if (!EmitType(out, type, sem->StorageClass(), sem->Access(),
                     builder_.Symbols().NameFor(var->symbol()))) {
         return false;
       }
@@ -1832,7 +1830,7 @@
       auto* type = sem->Type()->UnwrapRef();
 
       make_indent(out);
-      if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
+      if (!EmitType(out, type, sem->StorageClass(), sem->Access(),
                     builder_.Symbols().NameFor(var->symbol()))) {
         return false;
       }
@@ -1903,8 +1901,7 @@
 
       auto name = builder_.Symbols().NameFor(decl->symbol());
       auto* type = var->Type()->UnwrapRef();
-      if (!EmitType(out, type, var->StorageClass(), var->AccessControl(),
-                    name)) {
+      if (!EmitType(out, type, var->StorageClass(), var->Access(), name)) {
         return false;
       }
       if (!type->Is<sem::Array>()) {
@@ -1916,7 +1913,7 @@
       if (unwrapped_type->Is<sem::Texture>()) {
         register_space = "t";
         if (auto* storage_tex = unwrapped_type->As<sem::StorageTexture>()) {
-          if (storage_tex->access_control() != ast::AccessControl::kRead) {
+          if (storage_tex->access() != ast::Access::kRead) {
             register_space = "u";
           }
         }
@@ -2043,7 +2040,7 @@
     }
     first = false;
 
-    if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(), "")) {
+    if (!EmitType(out, type, sem->StorageClass(), sem->Access(), "")) {
       return false;
     }
 
@@ -2111,8 +2108,8 @@
   } else if (type->Is<sem::U32>()) {
     out << "0u";
   } else if (auto* vec = type->As<sem::Vector>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone,
-                  ast::AccessControl::kReadWrite, "")) {
+    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
+                  "")) {
       return false;
     }
     ScopedParen sp(out);
@@ -2125,8 +2122,8 @@
       }
     }
   } else if (auto* mat = type->As<sem::Matrix>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone,
-                  ast::AccessControl::kReadWrite, "")) {
+    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
+                  "")) {
       return false;
     }
     ScopedParen sp(out);
@@ -2326,10 +2323,10 @@
 bool GeneratorImpl::EmitType(std::ostream& out,
                              const sem::Type* type,
                              ast::StorageClass storage_class,
-                             ast::AccessControl::Access access_control,
+                             ast::Access access,
                              const std::string& name) {
   if (storage_class == ast::StorageClass::kStorage) {
-    if (access_control != ast::AccessControl::kRead) {
+    if (access != ast::Access::kRead) {
       out << "RW";
     }
     out << "ByteAddressBuffer";
@@ -2349,7 +2346,7 @@
       sizes.push_back(arr->Count());
       base_type = arr->ElemType();
     }
-    if (!EmitType(out, base_type, storage_class, access_control, "")) {
+    if (!EmitType(out, base_type, storage_class, access, "")) {
       return false;
     }
     if (!name.empty()) {
@@ -2365,7 +2362,7 @@
   } else if (type->Is<sem::I32>()) {
     out << "int";
   } else if (auto* mat = type->As<sem::Matrix>()) {
-    if (!EmitType(out, mat->type(), storage_class, access_control, "")) {
+    if (!EmitType(out, mat->type(), storage_class, access, "")) {
       return false;
     }
     // Note: HLSL's matrices are declared as <type>NxM, where N is the number of
@@ -2394,10 +2391,8 @@
     auto* multism = tex->As<sem::MultisampledTexture>();
     auto* sampled = tex->As<sem::SampledTexture>();
 
-    if (storage) {
-      if (access_control != ast::AccessControl::kRead) {
-        out << "RW";
-      }
+    if (storage && storage->access() != ast::Access::kRead) {
+      out << "RW";
     }
     out << "Texture";
 
@@ -2461,7 +2456,7 @@
       out << "uint" << size;
     } else {
       out << "vector<";
-      if (!EmitType(out, vec->type(), storage_class, access_control, "")) {
+      if (!EmitType(out, vec->type(), storage_class, access, "")) {
         return false;
       }
       out << ", " << size << ">";
@@ -2498,7 +2493,7 @@
 
     auto mem_name = builder_.Symbols().NameFor(mem->Declaration()->symbol());
     if (!EmitType(out, mem->Type(), ast::StorageClass::kNone,
-                  ast::AccessControl::kReadWrite, mem_name)) {
+                  ast::Access::kReadWrite, mem_name)) {
       return false;
     }
     // Array member name will be output with the type
@@ -2602,7 +2597,7 @@
   if (var->is_const()) {
     out << "const ";
   }
-  if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
+  if (!EmitType(out, type, sem->StorageClass(), sem->Access(),
                 builder_.Symbols().NameFor(var->symbol()))) {
     return false;
   }
@@ -2655,7 +2650,7 @@
     }
     out << "#endif" << std::endl;
     out << "static const ";
-    if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
+    if (!EmitType(out, type, sem->StorageClass(), sem->Access(),
                   builder_.Symbols().NameFor(var->symbol()))) {
       return false;
     }
@@ -2663,7 +2658,7 @@
         << kSpecConstantPrefix << const_id << ";" << std::endl;
   } else {
     out << "static const ";
-    if (!EmitType(out, type, sem->StorageClass(), sem->AccessControl(),
+    if (!EmitType(out, type, sem->StorageClass(), sem->Access(),
                   builder_.Symbols().NameFor(var->symbol()))) {
       return false;
     }
diff --git a/src/writer/hlsl/generator_impl.h b/src/writer/hlsl/generator_impl.h
index 9fee784..1b62c76 100644
--- a/src/writer/hlsl/generator_impl.h
+++ b/src/writer/hlsl/generator_impl.h
@@ -38,9 +38,6 @@
 
 // Forward declarations
 namespace sem {
-class AccessControl;
-}  // namespace sem
-namespace sem {
 class Call;
 class Intrinsic;
 }  // namespace sem
@@ -288,13 +285,13 @@
   /// @param out the output stream
   /// @param type the type to generate
   /// @param storage_class the storage class of the variable
-  /// @param access_control the access control type of the variable
+  /// @param access the access control type of the variable
   /// @param name the name of the variable, only used for array emission
   /// @returns true if the type is emitted
   bool EmitType(std::ostream& out,
                 const sem::Type* type,
                 ast::StorageClass storage_class,
-                ast::AccessControl::Access access_control,
+                ast::Access access,
                 const std::string& name);
   /// Handles generating a structure declaration
   /// @param out the output stream
diff --git a/src/writer/hlsl/generator_impl_function_test.cc b/src/writer/hlsl/generator_impl_function_test.cc
index b828607..e3b3d37 100644
--- a/src/writer/hlsl/generator_impl_function_test.cc
+++ b/src/writer/hlsl/generator_impl_function_test.cc
@@ -428,9 +428,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -474,9 +472,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -520,9 +516,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kWrite, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -563,9 +557,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -814,8 +806,7 @@
        Emit_Decoration_Called_By_EntryPoint_With_StorageBuffer) {
   auto* s = Structure("S", {Member("x", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -1064,9 +1055,7 @@
   auto* s = Structure("Data", {Member("d", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("data", ac, ast::StorageClass::kStorage,
+  Global("data", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/writer/hlsl/generator_impl_member_accessor_test.cc b/src/writer/hlsl/generator_impl_member_accessor_test.cc
index e155281..db9d468 100644
--- a/src/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -98,9 +98,7 @@
     auto* s =
         b.Structure("Data", members, {b.create<ast::StructBlockDecoration>()});
 
-    auto* ac_ty = b.ty.access(ast::AccessControl::kReadWrite, s);
-
-    b.Global("data", ac_ty, ast::StorageClass::kStorage, nullptr,
+    b.Global("data", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
              ast::DecorationList{
                  b.create<ast::BindingDecoration>(0),
                  b.create<ast::GroupDecoration>(1),
diff --git a/src/writer/hlsl/generator_impl_sanitizer_test.cc b/src/writer/hlsl/generator_impl_sanitizer_test.cc
index 7e16d5b..25a584a 100644
--- a/src/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -33,9 +33,8 @@
                           {
                               create<ast::StructBlockDecoration>(),
                           });
-  auto* ac_ty = ty.access(ast::AccessControl::kRead, sb_ty);
 
-  Global("sb", ac_ty, ast::StorageClass::kStorage,
+  Global("sb", sb_ty, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
diff --git a/src/writer/hlsl/generator_impl_type_test.cc b/src/writer/hlsl/generator_impl_type_test.cc
index 090e077..94dd0d6 100644
--- a/src/writer/hlsl/generator_impl_type_test.cc
+++ b/src/writer/hlsl/generator_impl_type_test.cc
@@ -38,7 +38,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, "ary"))
+                           ast::Access::kReadWrite, "ary"))
       << gen.error();
   EXPECT_EQ(result(), "bool ary[4]");
 }
@@ -50,7 +50,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, "ary"))
+                           ast::Access::kReadWrite, "ary"))
       << gen.error();
   EXPECT_EQ(result(), "bool ary[5][4]");
 }
@@ -64,7 +64,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, "ary"))
+                           ast::Access::kReadWrite, "ary"))
       << gen.error();
   EXPECT_EQ(result(), "bool ary[5][4][1]");
 }
@@ -76,7 +76,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, "ary"))
+                           ast::Access::kReadWrite, "ary"))
       << gen.error();
   EXPECT_EQ(result(), "bool ary[6][5][4]");
 }
@@ -88,7 +88,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "bool[4]");
 }
@@ -100,7 +100,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, "ary"))
+                           ast::Access::kReadWrite, "ary"))
       << gen.error();
   EXPECT_EQ(result(), "bool ary[]");
 }
@@ -111,7 +111,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "bool");
 }
@@ -122,7 +122,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "float");
 }
@@ -133,7 +133,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "int");
 }
@@ -146,7 +146,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "float2x3");
 }
@@ -159,7 +159,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, p, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "float*");
 }
@@ -189,8 +189,7 @@
                           Member("b", ty.f32()),
                       },
                       {create<ast::StructBlockDecoration>()});
-  Global("g", ty.access(ast::AccessControl::kReadWrite, s),
-         ast::StorageClass::kStorage,
+  Global("g", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -214,7 +213,7 @@
 
   auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
   ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "S");
 }
@@ -234,7 +233,7 @@
 
   auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
   ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(gen.result(), R"(struct S {
   int a;
@@ -290,7 +289,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "uint");
 }
@@ -302,7 +301,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "float3");
 }
@@ -313,7 +312,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "void");
 }
@@ -324,7 +323,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "SamplerState");
 }
@@ -335,7 +334,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "SamplerComparisonState");
 }
@@ -354,7 +353,7 @@
 
   auto* t = ty.depth_texture(params.dim);
 
-  Global("tex", t, ast::StorageClass::kNone, nullptr,
+  Global("tex", t,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
@@ -413,7 +412,7 @@
   }
   auto* t = ty.sampled_texture(params.dim, datatype);
 
-  Global("tex", t, ast::StorageClass::kNone, nullptr,
+  Global("tex", t,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
@@ -532,7 +531,7 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone,
-                           ast::AccessControl::kReadWrite, ""))
+                           ast::Access::kReadWrite, ""))
       << gen.error();
   EXPECT_EQ(result(), "Texture2DMS<float4>");
 }
@@ -552,11 +551,11 @@
 TEST_P(HlslStorageTexturesTest, Emit) {
   auto params = GetParam();
 
-  auto* t = ty.storage_texture(params.dim, params.imgfmt);
-  auto* ac = ty.access(
-      params.ro ? ast::AccessControl::kRead : ast::AccessControl::kWrite, t);
+  auto* t =
+      ty.storage_texture(params.dim, params.imgfmt,
+                         params.ro ? ast::Access::kRead : ast::Access::kWrite);
 
-  Global("tex", ac, ast::StorageClass::kNone, nullptr,
+  Global("tex", t,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
diff --git a/src/writer/msl/generator_impl.cc b/src/writer/msl/generator_impl.cc
index 6eec4df..f4d38fc 100644
--- a/src/writer/msl/generator_impl.cc
+++ b/src/writer/msl/generator_impl.cc
@@ -1326,7 +1326,7 @@
     }
     first = false;
 
-    if (var->AccessControl() == ast::AccessControl::kRead) {
+    if (var->Access() == ast::Access::kRead) {
       out_ << "const ";
     }
 
@@ -1544,7 +1544,7 @@
     auto* binding = data.second.binding;
     // auto* set = data.second.set;
 
-    if (var->AccessControl() == ast::AccessControl::kRead) {
+    if (var->Access() == ast::Access::kRead) {
       out_ << "const ";
     }
 
@@ -2037,9 +2037,9 @@
       }
 
       std::string access_str;
-      if (storage->access_control() == ast::AccessControl::kRead) {
+      if (storage->access() == ast::Access::kRead) {
         out_ << ", access::read";
-      } else if (storage->access_control() == ast::AccessControl::kWrite) {
+      } else if (storage->access() == ast::Access::kWrite) {
         out_ << ", access::write";
       } else {
         diagnostics_.add_error("Invalid access control for storage texture");
diff --git a/src/writer/msl/generator_impl_function_test.cc b/src/writer/msl/generator_impl_function_test.cc
index 7c19271..66df0a3 100644
--- a/src/writer/msl/generator_impl_function_test.cc
+++ b/src/writer/msl/generator_impl_function_test.cc
@@ -306,9 +306,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -354,9 +352,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -620,9 +616,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -679,9 +673,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-
-  Global("coord", ac, ast::StorageClass::kStorage,
+  Global("coord", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(1),
@@ -824,9 +816,7 @@
   auto* s = Structure("Data", {Member("d", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("data", ac, ast::StorageClass::kStorage,
+  Global("data", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/writer/msl/generator_impl_type_test.cc b/src/writer/msl/generator_impl_type_test.cc
index 235fc26..d45ead6 100644
--- a/src/writer/msl/generator_impl_type_test.cc
+++ b/src/writer/msl/generator_impl_type_test.cc
@@ -232,8 +232,7 @@
                 },
                 {create<ast::StructBlockDecoration>()});
 
-  Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage,
+  Global("G", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -342,8 +341,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage,
+  Global("G", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -437,8 +435,7 @@
                 },
                 ast::DecorationList{create<ast::StructBlockDecoration>()});
 
-  Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage,
+  Global("G", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -551,8 +548,7 @@
       },
       {create<ast::StructBlockDecoration>()});
 
-  Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage,
+  Global("G", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -617,8 +613,7 @@
                       },
                       {create<ast::StructBlockDecoration>()});
 
-  Global("G", ty.access(ast::AccessControl::kRead, s),
-         ast::StorageClass::kStorage,
+  Global("G", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -771,10 +766,10 @@
 TEST_P(MslStorageTexturesTest, Emit) {
   auto params = GetParam();
 
-  auto* s = ty.storage_texture(params.dim, ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(
-      params.ro ? ast::AccessControl::kRead : ast::AccessControl::kWrite, s);
-  Global("test_var", ac,
+  auto* s =
+      ty.storage_texture(params.dim, ast::ImageFormat::kR32Float,
+                         params.ro ? ast::Access::kRead : ast::Access::kWrite);
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -782,7 +777,7 @@
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(program->TypeOf(ac), "")) << gen.error();
+  ASSERT_TRUE(gen.EmitType(program->TypeOf(s), "")) << gen.error();
   EXPECT_EQ(gen.result(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
diff --git a/src/writer/spirv/builder.cc b/src/writer/spirv/builder.cc
index a076318..6ebafb9 100644
--- a/src/writer/spirv/builder.cc
+++ b/src/writer/spirv/builder.cc
@@ -786,20 +786,23 @@
   if (var->has_constructor()) {
     ops.push_back(Operand::Int(init_id));
   } else {
-    if (type->Is<sem::StorageTexture>() || type->Is<sem::Struct>()) {
+    auto* st = type->As<sem::StorageTexture>();
+    if (st || type->Is<sem::Struct>()) {
       // type is a sem::Struct or a sem::StorageTexture
-      switch (sem->AccessControl()) {
-        case ast::AccessControl::kWrite:
+      auto access = st ? st->access() : sem->Access();
+      switch (access) {
+        case ast::Access::kWrite:
           push_annot(
               spv::Op::OpDecorate,
               {Operand::Int(var_id), Operand::Int(SpvDecorationNonReadable)});
           break;
-        case ast::AccessControl::kRead:
+        case ast::Access::kRead:
           push_annot(
               spv::Op::OpDecorate,
               {Operand::Int(var_id), Operand::Int(SpvDecorationNonWritable)});
           break;
-        case ast::AccessControl::kReadWrite:
+        case ast::Access::kUndefined:
+        case ast::Access::kReadWrite:
           break;
       }
     }
@@ -3287,17 +3290,17 @@
         type_name_to_id_[builder_
                              .create<sem::StorageTexture>(
                                  st->dim(), st->image_format(),
-                                 ast::AccessControl::kRead, st->type())
+                                 ast::Access::kRead, st->type())
                              ->type_name()] = id;
         type_name_to_id_[builder_
                              .create<sem::StorageTexture>(
                                  st->dim(), st->image_format(),
-                                 ast::AccessControl::kWrite, st->type())
+                                 ast::Access::kWrite, st->type())
                              ->type_name()] = id;
         type_name_to_id_[builder_
                              .create<sem::StorageTexture>(
                                  st->dim(), st->image_format(),
-                                 ast::AccessControl::kReadWrite, st->type())
+                                 ast::Access::kReadWrite, st->type())
                              ->type_name()] = id;
       }
 
diff --git a/src/writer/spirv/builder.h b/src/writer/spirv/builder.h
index 6cdd12a..aa051c4 100644
--- a/src/writer/spirv/builder.h
+++ b/src/writer/spirv/builder.h
@@ -263,9 +263,9 @@
   /// @param type the type to generate for
   /// @param struct_id the struct id
   /// @param member_idx the member index
-  void GenerateMemberAccessControlIfNeeded(const sem::Type* type,
-                                           uint32_t struct_id,
-                                           uint32_t member_idx);
+  void GenerateMemberAccessIfNeeded(const sem::Type* type,
+                                    uint32_t struct_id,
+                                    uint32_t member_idx);
   /// Generates a function variable
   /// @param var the variable
   /// @returns true if the variable was generated
diff --git a/src/writer/spirv/builder_function_test.cc b/src/writer/spirv/builder_function_test.cc
index a3efcf7..d4ed7fb 100644
--- a/src/writer/spirv/builder_function_test.cc
+++ b/src/writer/spirv/builder_function_test.cc
@@ -204,9 +204,7 @@
   auto* s = Structure("Data", {Member("d", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("data", ac, ast::StorageClass::kStorage, nullptr,
+  Global("data", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/writer/spirv/builder_global_variable_test.cc b/src/writer/spirv/builder_global_variable_test.cc
index 622e7df..6cc49f9d 100644
--- a/src/writer/spirv/builder_global_variable_test.cc
+++ b/src/writer/spirv/builder_global_variable_test.cc
@@ -394,7 +394,7 @@
   // struct A {
   //   a : i32;
   // };
-  // var b : [[access(read)]] A
+  // var b<storage, read> : A
 
   auto* A = Structure("A",
                       {
@@ -402,9 +402,8 @@
                           Member("b", ty.i32()),
                       },
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, A);
 
-  auto* var = Global("b", ac, ast::StorageClass::kStorage,
+  auto* var = Global("b", A, ast::StorageClass::kStorage, ast::Access::kRead,
                      ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
@@ -438,14 +437,13 @@
   //   a : i32;
   // };
   // type B = A;
-  // var b : [[access(read)]] B
+  // var b<storage, read> : B
 
   auto* A = Structure("A", {Member("a", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
   auto* B = ty.alias("B", A);
   AST().AddConstructedType(B);
-  auto* ac = ty.access(ast::AccessControl::kRead, B);
-  auto* var = Global("b", ac, ast::StorageClass::kStorage,
+  auto* var = Global("b", B, ast::StorageClass::kStorage, ast::Access::kRead,
                      ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
@@ -476,15 +474,14 @@
   // struct A {
   //   a : i32;
   // };
-  // type B = [[access(read)]] A;
-  // var b : B
+  // type B = A;
+  // var<storage, read> b : B
 
   auto* A = Structure("A", {Member("a", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, A);
-  auto* B = ty.alias("B", ac);
+  auto* B = ty.alias("B", A);
   AST().AddConstructedType(B);
-  auto* var = Global("b", B, ast::StorageClass::kStorage,
+  auto* var = Global("b", B, ast::StorageClass::kStorage, ast::Access::kRead,
                      ast::DecorationList{
                          create<ast::BindingDecoration>(0),
                          create<ast::GroupDecoration>(0),
@@ -515,24 +512,22 @@
   // struct A {
   //   a : i32;
   // };
-  // var b : [[access(read)]] A
-  // var c : [[access(read_write)]] A
+  // var<storage, read> b : A
+  // var<storage, read_write> c : A
 
   auto* A = Structure("A", {Member("a", ty.i32())},
                       {create<ast::StructBlockDecoration>()});
-  auto* read = ty.access(ast::AccessControl::kRead, A);
-  auto* rw = ty.access(ast::AccessControl::kReadWrite, A);
-
-  auto* var_b = Global("b", read, ast::StorageClass::kStorage,
+  auto* var_b = Global("b", A, ast::StorageClass::kStorage, ast::Access::kRead,
                        ast::DecorationList{
                            create<ast::GroupDecoration>(0),
                            create<ast::BindingDecoration>(0),
                        });
-  auto* var_c = Global("c", rw, ast::StorageClass::kStorage,
-                       ast::DecorationList{
-                           create<ast::GroupDecoration>(1),
-                           create<ast::BindingDecoration>(0),
-                       });
+  auto* var_c =
+      Global("c", A, ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             ast::DecorationList{
+                 create<ast::GroupDecoration>(1),
+                 create<ast::BindingDecoration>(0),
+             });
 
   spirv::Builder& b = Build();
 
@@ -562,14 +557,13 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TextureStorageReadOnly) {
-  // var<uniform_constant> a : [[access(read)]] texture_storage_2d<r32uint>;
+  // var<uniform_constant> a : texture_storage_2d<r32uint, read>;
 
-  auto* type = ty.storage_texture(ast::TextureDimension::k2d,
-                                  ast::ImageFormat::kR32Uint);
+  auto* type =
+      ty.storage_texture(ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint,
+                         ast::Access::kRead);
 
-  auto* ac = ty.access(ast::AccessControl::kRead, type);
-
-  auto* var_a = Global("a", ac, ast::StorageClass::kNone,
+  auto* var_a = Global("a", type,
                        ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
@@ -591,14 +585,13 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
-  // var<uniform_constant> a : [[access(write)]] texture_storage_2d<r32uint>;
+  // var<uniform_constant> a : texture_storage_2d<r32uint, write>;
 
-  auto* type = ty.storage_texture(ast::TextureDimension::k2d,
-                                  ast::ImageFormat::kR32Uint);
+  auto* type =
+      ty.storage_texture(ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint,
+                         ast::Access::kWrite);
 
-  auto* ac = ty.access(ast::AccessControl::kWrite, type);
-
-  auto* var_a = Global("a", ac, ast::StorageClass::kNone,
+  auto* var_a = Global("a", type,
                        ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
@@ -622,21 +615,21 @@
 // Check that multiple texture_storage types with different access modifiers
 // only produces a single OpTypeImage.
 TEST_F(BuilderTest, GlobalVar_TextureStorageWithDifferentAccess) {
-  // var<uniform_constant> a : [[access(read)]] texture_storage_2d<r32uint>;
-  // var<uniform_constant> b : [[access(write)]] texture_storage_2d<r32uint>;
+  // var<uniform_constant> a : texture_storage_2d<r32uint, read>;
+  // var<uniform_constant> b : texture_storage_2d<r32uint, write>;
 
-  auto* type_a = ty.access(ast::AccessControl::kRead,
-                           ty.storage_texture(ast::TextureDimension::k2d,
-                                              ast::ImageFormat::kR32Uint));
+  auto* type_a =
+      ty.storage_texture(ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint,
+                         ast::Access::kRead);
   auto* var_a = Global("a", type_a, ast::StorageClass::kNone,
                        ast::DecorationList{
                            create<ast::BindingDecoration>(0),
                            create<ast::GroupDecoration>(0),
                        });
 
-  auto* type_b = ty.access(ast::AccessControl::kWrite,
-                           ty.storage_texture(ast::TextureDimension::k2d,
-                                              ast::ImageFormat::kR32Uint));
+  auto* type_b =
+      ty.storage_texture(ast::TextureDimension::k2d, ast::ImageFormat::kR32Uint,
+                         ast::Access::kWrite);
   auto* var_b = Global("b", type_b, ast::StorageClass::kNone,
                        ast::DecorationList{
                            create<ast::BindingDecoration>(1),
diff --git a/src/writer/spirv/builder_intrinsic_test.cc b/src/writer/spirv/builder_intrinsic_test.cc
index 6a09d5c..ebc1de3 100644
--- a/src/writer/spirv/builder_intrinsic_test.cc
+++ b/src/writer/spirv/builder_intrinsic_test.cc
@@ -1537,8 +1537,7 @@
 TEST_F(IntrinsicBuilderTest, Call_ArrayLength) {
   auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))},
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-  Global("b", ac, ast::StorageClass::kStorage, nullptr,
+  Global("b", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
@@ -1587,8 +1586,7 @@
                           Member(4, "a", ty.array<f32>(4)),
                       },
                       {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
-  Global("b", ac, ast::StorageClass::kStorage, nullptr,
+  Global("b", s, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(1),
              create<ast::GroupDecoration>(2),
diff --git a/src/writer/spirv/builder_type_test.cc b/src/writer/spirv/builder_type_test.cc
index 83168ca..2200436 100644
--- a/src/writer/spirv/builder_type_test.cc
+++ b/src/writer/spirv/builder_type_test.cc
@@ -30,8 +30,7 @@
   auto* ary = ty.array(ty.i32(), 0);
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage,
+  Global("a", str, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -52,8 +51,7 @@
   auto* ary = ty.array(ty.i32(), 0);
   auto* str = Structure("S", {Member("x", ary)},
                         {create<ast::StructBlockDecoration>()});
-  auto* ac = ty.access(ast::AccessControl::kRead, str);
-  Global("a", ac, ast::StorageClass::kStorage,
+  Global("a", str, ast::StorageClass::kStorage, ast::Access::kRead,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -831,10 +829,9 @@
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
   auto* s = ty.storage_texture(ast::TextureDimension::k1d,
-                               ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Float, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -851,10 +848,9 @@
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Float, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -871,10 +867,9 @@
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
   auto* s = ty.storage_texture(ast::TextureDimension::k2dArray,
-                               ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Float, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -891,10 +886,9 @@
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
   auto* s = ty.storage_texture(ast::TextureDimension::k3d,
-                               ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Float, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -912,10 +906,9 @@
 TEST_F(BuilderTest_Type,
        StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::ImageFormat::kR32Float);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Float, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -933,10 +926,9 @@
 TEST_F(BuilderTest_Type,
        StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::ImageFormat::kR32Sint);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Sint, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -954,10 +946,9 @@
 TEST_F(BuilderTest_Type,
        StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
   auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::ImageFormat::kR32Uint);
-  auto* ac = ty.access(ast::AccessControl::kRead, s);
+                               ast::ImageFormat::kR32Uint, ast::Access::kRead);
 
-  Global("test_var", ac,
+  Global("test_var", s,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
diff --git a/src/writer/wgsl/generator_impl.cc b/src/writer/wgsl/generator_impl.cc
index 8bba93a..789bb51 100644
--- a/src/writer/wgsl/generator_impl.cc
+++ b/src/writer/wgsl/generator_impl.cc
@@ -17,7 +17,7 @@
 #include <algorithm>
 #include <limits>
 
-#include "src/ast/access_control.h"
+#include "src/ast/access.h"
 #include "src/ast/alias.h"
 #include "src/ast/array.h"
 #include "src/ast/bool.h"
@@ -355,25 +355,26 @@
   return true;
 }
 
-bool GeneratorImpl::EmitType(const ast::Type* ty) {
-  if (auto* ac = ty->As<ast::AccessControl>()) {
-    out_ << "[[access(";
-    if (ac->IsReadOnly()) {
+bool GeneratorImpl::EmitAccess(const ast::Access access) {
+  switch (access) {
+    case ast::Access::kRead:
       out_ << "read";
-    } else if (ac->IsWriteOnly()) {
+      return true;
+    case ast::Access::kWrite:
       out_ << "write";
-    } else if (ac->IsReadWrite()) {
+      return true;
+    case ast::Access::kReadWrite:
       out_ << "read_write";
-    } else {
-      diagnostics_.add_error("invalid access control");
-      return false;
-    }
-    out_ << ")]] ";
-    if (!EmitType(ac->type())) {
-      return false;
-    }
-    return true;
-  } else if (auto* alias = ty->As<ast::Alias>()) {
+      return true;
+    default:
+      break;
+  }
+  diagnostics_.add_error("unknown access");
+  return false;
+}
+
+bool GeneratorImpl::EmitType(const ast::Type* ty) {
+  if (auto* alias = ty->As<ast::Alias>()) {
     out_ << program_->Symbols().NameFor(alias->symbol());
   } else if (auto* ary = ty->As<ast::Array>()) {
     for (auto* deco : ary->decorations()) {
@@ -477,6 +478,10 @@
       if (!EmitImageFormat(storage->image_format())) {
         return false;
       }
+      out_ << ", ";
+      if (!EmitAccess(storage->access())) {
+        return false;
+      }
       out_ << ">";
     }
 
@@ -580,8 +585,16 @@
   } else {
     out_ << "var";
     auto sc = var->declared_storage_class();
-    if (sc != ast::StorageClass::kNone) {
-      out_ << "<" << sc << ">";
+    auto ac = var->declared_access();
+    if (sc != ast::StorageClass::kNone || ac != ast::Access::kUndefined) {
+      out_ << "<" << sc;
+      if (ac != ast::Access::kUndefined) {
+        out_ << ", ";
+        if (!EmitAccess(ac)) {
+          return false;
+        }
+      }
+      out_ << ">";
     }
   }
 
diff --git a/src/writer/wgsl/generator_impl.h b/src/writer/wgsl/generator_impl.h
index ecb17a5..1017bae 100644
--- a/src/writer/wgsl/generator_impl.h
+++ b/src/writer/wgsl/generator_impl.h
@@ -174,6 +174,10 @@
   /// @param fmt the format to generate
   /// @returns true if the format is emitted
   bool EmitImageFormat(const ast::ImageFormat fmt);
+  /// Handles emitting an access control
+  /// @param access the access to generate
+  /// @returns true if the access is emitted
+  bool EmitAccess(const ast::Access access);
   /// Handles emitting a type constructor
   /// @param expr the type constructor expression
   /// @returns true if the constructor is emitted
diff --git a/src/writer/wgsl/generator_impl_function_test.cc b/src/writer/wgsl/generator_impl_function_test.cc
index 97bf435..5bb305a 100644
--- a/src/writer/wgsl/generator_impl_function_test.cc
+++ b/src/writer/wgsl/generator_impl_function_test.cc
@@ -175,9 +175,7 @@
   auto* s = Structure("Data", {Member("d", ty.f32())},
                       {create<ast::StructBlockDecoration>()});
 
-  auto* ac = ty.access(ast::AccessControl::kReadWrite, s);
-
-  Global("data", ac, ast::StorageClass::kStorage, nullptr,
+  Global("data", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
          ast::DecorationList{
              create<ast::BindingDecoration>(0),
              create<ast::GroupDecoration>(0),
@@ -219,7 +217,7 @@
   d : f32;
 };
 
-[[binding(0), group(0)]] var<storage> data : [[access(read_write)]] Data;
+[[binding(0), group(0)]] var<storage, read_write> data : Data;
 
 [[stage(compute)]]
 fn a() {
diff --git a/src/writer/wgsl/generator_impl_global_decl_test.cc b/src/writer/wgsl/generator_impl_global_decl_test.cc
index 45bb89f..5954621 100644
--- a/src/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/writer/wgsl/generator_impl_global_decl_test.cc
@@ -116,7 +116,7 @@
 
 TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
   auto* st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  Global("t", ty.access(ast::AccessControl::kRead, st),
+  Global("t", st,
          ast::DecorationList{
              create<ast::GroupDecoration>(0),
              create<ast::BindingDecoration>(0),
@@ -127,9 +127,8 @@
   gen.increment_indent();
 
   ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(
-      gen.result(),
-      "  [[group(0), binding(0)]] var t : [[access(read)]] texture_1d<f32>;\n");
+  EXPECT_EQ(gen.result(),
+            "  [[group(0), binding(0)]] var t : texture_1d<f32>;\n");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_OverridableConstants) {
diff --git a/src/writer/wgsl/generator_impl_type_test.cc b/src/writer/wgsl/generator_impl_type_test.cc
index d217bfb..5bb5abd 100644
--- a/src/writer/wgsl/generator_impl_type_test.cc
+++ b/src/writer/wgsl/generator_impl_type_test.cc
@@ -45,32 +45,6 @@
   EXPECT_EQ(gen.result(), "array<bool, 4>");
 }
 
-TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_Read) {
-  auto* s = Structure("S", {Member("a", ty.i32())},
-                      {create<ast::StructBlockDecoration>()});
-
-  auto* a = ty.access(ast::AccessControl::kRead, s);
-  AST().AddConstructedType(ty.alias("make_type_reachable", a));
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
-  EXPECT_EQ(gen.result(), "[[access(read)]] S");
-}
-
-TEST_F(WgslGeneratorImplTest, EmitType_AccessControl_ReadWrite) {
-  auto* s = Structure("S", {Member("a", ty.i32())},
-                      {create<ast::StructBlockDecoration>()});
-
-  auto* a = ty.access(ast::AccessControl::kReadWrite, s);
-  AST().AddConstructedType(ty.alias("make_type_reachable", a));
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.EmitType(a)) << gen.error();
-  EXPECT_EQ(gen.result(), "[[access(read_write)]] S");
-}
-
 TEST_F(WgslGeneratorImplTest, EmitType_Array_Decoration) {
   auto* a = ty.array(ty.bool_(), 4, 16u);
   AST().AddConstructedType(ty.alias("make_type_reachable", a));
@@ -416,7 +390,7 @@
 struct StorageTextureData {
   ast::ImageFormat fmt;
   ast::TextureDimension dim;
-  ast::AccessControl::Access access;
+  ast::Access access;
   const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageTextureData data) {
@@ -427,12 +401,11 @@
 TEST_P(WgslGenerator_StorageTextureTest, EmitType_StorageTexture) {
   auto param = GetParam();
 
-  auto* t = ty.storage_texture(param.dim, param.fmt);
-  auto* ac = ty.access(param.access, t);
+  auto* t = ty.storage_texture(param.dim, param.fmt, param.access);
 
   GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitType(ac)) << gen.error();
+  ASSERT_TRUE(gen.EmitType(t)) << gen.error();
   EXPECT_EQ(gen.result(), param.name);
 }
 INSTANTIATE_TEST_SUITE_P(
@@ -440,37 +413,29 @@
     WgslGenerator_StorageTextureTest,
     testing::Values(
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k1d,
-                           ast::AccessControl::kRead,
-                           "[[access(read)]] texture_storage_1d<r8unorm>"},
+                           ast::TextureDimension::k1d, ast::Access::kRead,
+                           "texture_storage_1d<r8unorm, read>"},
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k2d,
-                           ast::AccessControl::kRead,
-                           "[[access(read)]] texture_storage_2d<r8unorm>"},
-        StorageTextureData{
-            ast::ImageFormat::kR8Unorm, ast::TextureDimension::k2dArray,
-            ast::AccessControl::kRead,
-            "[[access(read)]] texture_storage_2d_array<r8unorm>"},
+                           ast::TextureDimension::k2d, ast::Access::kRead,
+                           "texture_storage_2d<r8unorm, read>"},
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k3d,
-                           ast::AccessControl::kRead,
-                           "[[access(read)]] texture_storage_3d<r8unorm>"},
+                           ast::TextureDimension::k2dArray, ast::Access::kRead,
+                           "texture_storage_2d_array<r8unorm, read>"},
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k1d,
-                           ast::AccessControl::kWrite,
-                           "[[access(write)]] texture_storage_1d<r8unorm>"},
+                           ast::TextureDimension::k3d, ast::Access::kRead,
+                           "texture_storage_3d<r8unorm, read>"},
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k2d,
-                           ast::AccessControl::kWrite,
-                           "[[access(write)]] texture_storage_2d<r8unorm>"},
-        StorageTextureData{
-            ast::ImageFormat::kR8Unorm, ast::TextureDimension::k2dArray,
-            ast::AccessControl::kWrite,
-            "[[access(write)]] texture_storage_2d_array<r8unorm>"},
+                           ast::TextureDimension::k1d, ast::Access::kWrite,
+                           "texture_storage_1d<r8unorm, write>"},
         StorageTextureData{ast::ImageFormat::kR8Unorm,
-                           ast::TextureDimension::k3d,
-                           ast::AccessControl::kWrite,
-                           "[[access(write)]] texture_storage_3d<r8unorm>"}));
+                           ast::TextureDimension::k2d, ast::Access::kWrite,
+                           "texture_storage_2d<r8unorm, write>"},
+        StorageTextureData{ast::ImageFormat::kR8Unorm,
+                           ast::TextureDimension::k2dArray, ast::Access::kWrite,
+                           "texture_storage_2d_array<r8unorm, write>"},
+        StorageTextureData{ast::ImageFormat::kR8Unorm,
+                           ast::TextureDimension::k3d, ast::Access::kWrite,
+                           "texture_storage_3d<r8unorm, write>"}));
 
 struct ImageFormatData {
   ast::ImageFormat fmt;
diff --git a/src/writer/wgsl/generator_impl_variable_test.cc b/src/writer/wgsl/generator_impl_variable_test.cc
index 0605aac..8b51c3a 100644
--- a/src/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/writer/wgsl/generator_impl_variable_test.cc
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "src/ast/override_decoration.h"
+#include "src/ast/struct_block_decoration.h"
 #include "src/writer/wgsl/test_helper.h"
 
 namespace tint {
@@ -42,6 +43,54 @@
 )");
 }
 
+TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
+  auto* s = Structure("S", {Member("a", ty.i32())},
+                      {create<ast::StructBlockDecoration>()});
+  auto* v = Global("a", s, ast::StorageClass::kStorage, ast::Access::kRead,
+                   ast::DecorationList{
+                       create<ast::BindingDecoration>(0),
+                       create<ast::GroupDecoration>(0),
+                   });
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
+  EXPECT_EQ(gen.result(), R"([[binding(0), group(0)]] var<storage, read> a : S;
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Write) {
+  auto* s = Structure("S", {Member("a", ty.i32())},
+                      {create<ast::StructBlockDecoration>()});
+  auto* v = Global("a", s, ast::StorageClass::kStorage, ast::Access::kWrite,
+                   ast::DecorationList{
+                       create<ast::BindingDecoration>(0),
+                       create<ast::GroupDecoration>(0),
+                   });
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
+  EXPECT_EQ(gen.result(), R"([[binding(0), group(0)]] var<storage, write> a : S;
+)");
+}
+
+TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
+  auto* s = Structure("S", {Member("a", ty.i32())},
+                      {create<ast::StructBlockDecoration>()});
+  auto* v = Global("a", s, ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                   ast::DecorationList{
+                       create<ast::BindingDecoration>(0),
+                       create<ast::GroupDecoration>(0),
+                   });
+
+  GeneratorImpl& gen = Build();
+
+  ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
+  EXPECT_EQ(gen.result(),
+            R"([[binding(0), group(0)]] var<storage, read_write> a : S;
+)");
+}
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
   auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
                    ast::DecorationList{
@@ -65,9 +114,8 @@
   GeneratorImpl& gen = Build();
 
   ASSERT_TRUE(gen.EmitVariable(v)) << gen.error();
-  EXPECT_EQ(
-      gen.result(),
-      R"([[builtin(position), location(2)]] var<private> a : f32;
+  EXPECT_EQ(gen.result(),
+            R"([[builtin(position), location(2)]] var<private> a : f32;
 )");
 }
 
diff --git a/test/BUILD.gn b/test/BUILD.gn
index ac376f8..dd98264 100644
--- a/test/BUILD.gn
+++ b/test/BUILD.gn
@@ -146,7 +146,6 @@
 
 tint_unittests_source_set("tint_unittests_core_src") {
   sources = [
-    "../src/ast/access_control_test.cc",
     "../src/ast/access_decoration_test.cc",
     "../src/ast/alias_test.cc",
     "../src/ast/array_accessor_expression_test.cc",
@@ -467,7 +466,7 @@
     "../src/reader/wgsl/parser_impl_variable_decoration_test.cc",
     "../src/reader/wgsl/parser_impl_variable_ident_decl_test.cc",
     "../src/reader/wgsl/parser_impl_variable_stmt_test.cc",
-    "../src/reader/wgsl/parser_impl_variable_storage_decoration_test.cc",
+    "../src/reader/wgsl/parser_impl_variable_qualifier_test.cc",
     "../src/reader/wgsl/parser_test.cc",
     "../src/reader/wgsl/token_test.cc",
   ]
diff --git a/test/array/assign_to_function_var.wgsl b/test/array/assign_to_function_var.wgsl
index 043fb8c..aba7c60 100644
--- a/test/array/assign_to_function_var.wgsl
+++ b/test/array/assign_to_function_var.wgsl
@@ -8,7 +8,7 @@
 var<private> src_private : ArrayType;
 var<workgroup> src_workgroup : ArrayType;
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 fn ret_arr() -> ArrayType {
   return ArrayType();
diff --git a/test/array/assign_to_function_var.wgsl.expected.wgsl b/test/array/assign_to_function_var.wgsl.expected.wgsl
index 7b23ed6..0ab9c0f 100644
--- a/test/array/assign_to_function_var.wgsl.expected.wgsl
+++ b/test/array/assign_to_function_var.wgsl.expected.wgsl
@@ -11,7 +11,7 @@
 
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
 
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 fn ret_arr() -> ArrayType {
   return ArrayType();
diff --git a/test/array/assign_to_private_var.wgsl b/test/array/assign_to_private_var.wgsl
index 1c32ee3..194c041 100644
--- a/test/array/assign_to_private_var.wgsl
+++ b/test/array/assign_to_private_var.wgsl
@@ -8,7 +8,7 @@
 var<private> src_private : ArrayType;
 var<workgroup> src_workgroup : ArrayType;
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 var<private> dst : ArrayType;
 var<private> dst_nested : array<array<array<i32, 2>, 3>, 4>;
diff --git a/test/array/assign_to_private_var.wgsl.expected.wgsl b/test/array/assign_to_private_var.wgsl.expected.wgsl
index af9c38e..ab6e8c7 100644
--- a/test/array/assign_to_private_var.wgsl.expected.wgsl
+++ b/test/array/assign_to_private_var.wgsl.expected.wgsl
@@ -11,7 +11,7 @@
 
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
 
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 var<private> dst : ArrayType;
 
diff --git a/test/array/assign_to_storage_var.wgsl b/test/array/assign_to_storage_var.wgsl
index 5754a22..b50f0dd 100644
--- a/test/array/assign_to_storage_var.wgsl
+++ b/test/array/assign_to_storage_var.wgsl
@@ -13,10 +13,10 @@
 var<private> src_private : ArrayType;
 var<workgroup> src_workgroup : ArrayType;
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
-[[group(0), binding(2)]] var<storage> dst : [[access(read_write)]] S;
-[[group(0), binding(3)]] var<storage> dst_nested : [[access(read_write)]] S_nested;
+[[group(0), binding(2)]] var<storage, read_write> dst : S;
+[[group(0), binding(3)]] var<storage, read_write> dst_nested : S_nested;
 
 fn ret_arr() -> ArrayType {
   return ArrayType();
diff --git a/test/array/assign_to_storage_var.wgsl.expected.wgsl b/test/array/assign_to_storage_var.wgsl.expected.wgsl
index 6508595..4c2228d 100644
--- a/test/array/assign_to_storage_var.wgsl.expected.wgsl
+++ b/test/array/assign_to_storage_var.wgsl.expected.wgsl
@@ -16,11 +16,11 @@
 
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
 
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
-[[group(0), binding(2)]] var<storage> dst : [[access(read_write)]] S;
+[[group(0), binding(2)]] var<storage, read_write> dst : S;
 
-[[group(0), binding(3)]] var<storage> dst_nested : [[access(read_write)]] S_nested;
+[[group(0), binding(3)]] var<storage, read_write> dst_nested : S_nested;
 
 fn ret_arr() -> ArrayType {
   return ArrayType();
diff --git a/test/array/assign_to_workgroup_var.wgsl b/test/array/assign_to_workgroup_var.wgsl
index 675daf6..f2b237c 100644
--- a/test/array/assign_to_workgroup_var.wgsl
+++ b/test/array/assign_to_workgroup_var.wgsl
@@ -8,7 +8,7 @@
 var<private> src_private : ArrayType;
 var<workgroup> src_workgroup : ArrayType;
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 var<workgroup> dst : ArrayType;
 var<workgroup> dst_nested : array<array<array<i32, 2>, 3>, 4>;
diff --git a/test/array/assign_to_workgroup_var.wgsl.expected.wgsl b/test/array/assign_to_workgroup_var.wgsl.expected.wgsl
index 8816948..c19bd6f 100644
--- a/test/array/assign_to_workgroup_var.wgsl.expected.wgsl
+++ b/test/array/assign_to_workgroup_var.wgsl.expected.wgsl
@@ -11,7 +11,7 @@
 
 [[group(0), binding(0)]] var<uniform> src_uniform : S;
 
-[[group(0), binding(1)]] var<storage> src_storage : [[access(read_write)]] S;
+[[group(0), binding(1)]] var<storage, read_write> src_storage : S;
 
 var<workgroup> dst : ArrayType;
 
diff --git a/test/bug/tint/221.wgsl b/test/bug/tint/221.wgsl
index f764d71..5e2c9ff 100644
--- a/test/bug/tint/221.wgsl
+++ b/test/bug/tint/221.wgsl
@@ -6,7 +6,7 @@
   data : Arr;
 };
 
-[[group(0), binding (0)]] var<storage>  b : [[access(read_write)]] Buf;
+[[group(0), binding (0)]] var<storage, read_write> b : Buf;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/bug/tint/221.wgsl.expected.wgsl b/test/bug/tint/221.wgsl.expected.wgsl
index d7130c8..205d295 100644
--- a/test/bug/tint/221.wgsl.expected.wgsl
+++ b/test/bug/tint/221.wgsl.expected.wgsl
@@ -6,7 +6,7 @@
   data : Arr;
 };
 
-[[group(0), binding(0)]] var<storage> b : [[access(read_write)]] Buf;
+[[group(0), binding(0)]] var<storage, read_write> b : Buf;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/bug/tint/492.wgsl b/test/bug/tint/492.wgsl
index 453796b..997a367 100644
--- a/test/bug/tint/492.wgsl
+++ b/test/bug/tint/492.wgsl
@@ -1,5 +1,5 @@
 [[block]] struct S { a : i32; };
-[[group(0), binding(0)]] var<storage> buf : [[access(read_write)]] S;
+[[group(0), binding(0)]] var<storage, read_write> buf : S;
 
 [[stage(compute)]] fn main() {
   let p : ptr<storage, i32> = &buf.a;
diff --git a/test/bug/tint/492.wgsl.expected.wgsl b/test/bug/tint/492.wgsl.expected.wgsl
index 821566a..024d407 100644
--- a/test/bug/tint/492.wgsl.expected.wgsl
+++ b/test/bug/tint/492.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   a : i32;
 };
 
-[[group(0), binding(0)]] var<storage> buf : [[access(read_write)]] S;
+[[group(0), binding(0)]] var<storage, read_write> buf : S;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/bug/tint/744.wgsl b/test/bug/tint/744.wgsl
index 8950ed5..72db750 100644
--- a/test/bug/tint/744.wgsl
+++ b/test/bug/tint/744.wgsl
@@ -7,9 +7,9 @@
     numbers: array<u32>;
 };
 
-[[group(0), binding(0)]] var<storage> firstMatrix : [[access(read)]] Matrix;
-[[group(0), binding(1)]] var<storage> secondMatrix : [[access(read)]] Matrix;
-[[group(0), binding(2)]] var<storage> resultMatrix : [[access(write)]] Matrix;
+[[group(0), binding(0)]] var<storage, read> firstMatrix : Matrix;
+[[group(0), binding(1)]] var<storage, read> secondMatrix : Matrix;
+[[group(0), binding(2)]] var<storage, write> resultMatrix : Matrix;
 [[group(0), binding(3)]] var<uniform> uniforms : Uniforms;
 
 [[stage(compute), workgroup_size(2,2,1)]]
diff --git a/test/bug/tint/744.wgsl.expected.wgsl b/test/bug/tint/744.wgsl.expected.wgsl
index cc4acca..d96d510 100644
--- a/test/bug/tint/744.wgsl.expected.wgsl
+++ b/test/bug/tint/744.wgsl.expected.wgsl
@@ -10,11 +10,11 @@
   numbers : array<u32>;
 };
 
-[[group(0), binding(0)]] var<storage> firstMatrix : [[access(read)]] Matrix;
+[[group(0), binding(0)]] var<storage, read> firstMatrix : Matrix;
 
-[[group(0), binding(1)]] var<storage> secondMatrix : [[access(read)]] Matrix;
+[[group(0), binding(1)]] var<storage, read> secondMatrix : Matrix;
 
-[[group(0), binding(2)]] var<storage> resultMatrix : [[access(write)]] Matrix;
+[[group(0), binding(2)]] var<storage, write> resultMatrix : Matrix;
 
 [[group(0), binding(3)]] var<uniform> uniforms : Uniforms;
 
diff --git a/test/deprecated/access_deco/storage_buffer.wgsl b/test/deprecated/access_deco/storage_buffer.wgsl
new file mode 100644
index 0000000..3948107
--- /dev/null
+++ b/test/deprecated/access_deco/storage_buffer.wgsl
@@ -0,0 +1,12 @@
+
+[[block]]
+struct SB {
+  a : f32;
+};
+
+[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+
+[[stage(compute)]]
+fn main() {
+  var x : f32 = sb.a;
+}
diff --git a/test/deprecated/access_deco/storage_buffer.wgsl.expected.hlsl b/test/deprecated/access_deco/storage_buffer.wgsl.expected.hlsl
new file mode 100644
index 0000000..b688127
--- /dev/null
+++ b/test/deprecated/access_deco/storage_buffer.wgsl.expected.hlsl
@@ -0,0 +1,13 @@
+deprecated/access_deco/storage_buffer.wgsl:7:26 warning: use of deprecated language feature: declare access with var<storage, read_write> instead of using [[access]] decoration
+[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+                         ^^^
+
+
+RWByteAddressBuffer sb : register(u0, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  float x = asfloat(sb.Load(0u));
+  return;
+}
+
diff --git a/test/deprecated/access_deco/storage_buffer.wgsl.expected.msl b/test/deprecated/access_deco/storage_buffer.wgsl.expected.msl
new file mode 100644
index 0000000..666ca66
--- /dev/null
+++ b/test/deprecated/access_deco/storage_buffer.wgsl.expected.msl
@@ -0,0 +1,16 @@
+deprecated/access_deco/storage_buffer.wgsl:7:26 warning: use of deprecated language feature: declare access with var<storage, read_write> instead of using [[access]] decoration
+[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+                         ^^^
+
+#include <metal_stdlib>
+
+using namespace metal;
+struct SB {
+  /* 0x0000 */ float a;
+};
+
+kernel void tint_symbol(device SB& sb [[buffer(0)]]) {
+  float x = sb.a;
+  return;
+}
+
diff --git a/test/deprecated/access_deco/storage_buffer.wgsl.expected.spvasm b/test/deprecated/access_deco/storage_buffer.wgsl.expected.spvasm
new file mode 100644
index 0000000..0736052
--- /dev/null
+++ b/test/deprecated/access_deco/storage_buffer.wgsl.expected.spvasm
@@ -0,0 +1,41 @@
+deprecated/access_deco/storage_buffer.wgsl:7:26 warning: use of deprecated language feature: declare access with var<storage, read_write> instead of using [[access]] decoration
+[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+                         ^^^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 17
+; Schema: 0
+               OpCapability Shader
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %SB "SB"
+               OpMemberName %SB 0 "a"
+               OpName %sb "sb"
+               OpName %main "main"
+               OpName %x "x"
+               OpDecorate %SB Block
+               OpMemberDecorate %SB 0 Offset 0
+               OpDecorate %sb DescriptorSet 0
+               OpDecorate %sb Binding 0
+      %float = OpTypeFloat 32
+         %SB = OpTypeStruct %float
+%_ptr_StorageBuffer_SB = OpTypePointer StorageBuffer %SB
+         %sb = OpVariable %_ptr_StorageBuffer_SB StorageBuffer
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+       %uint = OpTypeInt 32 0
+     %uint_0 = OpConstant %uint 0
+%_ptr_StorageBuffer_float = OpTypePointer StorageBuffer %float
+%_ptr_Function_float = OpTypePointer Function %float
+         %16 = OpConstantNull %float
+       %main = OpFunction %void None %5
+          %8 = OpLabel
+          %x = OpVariable %_ptr_Function_float Function %16
+         %12 = OpAccessChain %_ptr_StorageBuffer_float %sb %uint_0
+         %13 = OpLoad %float %12
+               OpStore %x %13
+               OpReturn
+               OpFunctionEnd
diff --git a/test/deprecated/access_deco/storage_buffer.wgsl.expected.wgsl b/test/deprecated/access_deco/storage_buffer.wgsl.expected.wgsl
new file mode 100644
index 0000000..4e23308
--- /dev/null
+++ b/test/deprecated/access_deco/storage_buffer.wgsl.expected.wgsl
@@ -0,0 +1,15 @@
+deprecated/access_deco/storage_buffer.wgsl:7:26 warning: use of deprecated language feature: declare access with var<storage, read_write> instead of using [[access]] decoration
+[[group(0), binding(0)]] var<storage> sb : [[access(read_write)]] SB;
+                         ^^^
+
+[[block]]
+struct SB {
+  a : f32;
+};
+
+[[group(0), binding(0)]] var<storage, read_write> sb : SB;
+
+[[stage(compute)]]
+fn main() {
+  var x : f32 = sb.a;
+}
diff --git a/test/deprecated/access_deco/storage_texture.wgsl b/test/deprecated/access_deco/storage_texture.wgsl
new file mode 100644
index 0000000..17cd7fd
--- /dev/null
+++ b/test/deprecated/access_deco/storage_texture.wgsl
@@ -0,0 +1,6 @@
+[[group(0), binding(0)]] var tex : [[access(write)]] texture_storage_2d<rgba32float>;
+
+[[stage(compute)]]
+fn main() {
+  var x : vec2<i32> = textureDimensions(tex);
+}
diff --git a/test/deprecated/access_deco/storage_texture.wgsl.expected.hlsl b/test/deprecated/access_deco/storage_texture.wgsl.expected.hlsl
new file mode 100644
index 0000000..59a6564
--- /dev/null
+++ b/test/deprecated/access_deco/storage_texture.wgsl.expected.hlsl
@@ -0,0 +1,14 @@
+deprecated/access_deco/storage_texture.wgsl:1:84 warning: use of deprecated language feature: access control is expected as last parameter of storage textures
+[[group(0), binding(0)]] var tex : [[access(write)]] texture_storage_2d<rgba32float>;
+                                                                                   ^
+
+RWTexture2D<float4> tex : register(u0, space0);
+
+[numthreads(1, 1, 1)]
+void main() {
+  int2 tint_tmp;
+  tex.GetDimensions(tint_tmp.x, tint_tmp.y);
+  int2 x = tint_tmp;
+  return;
+}
+
diff --git a/test/deprecated/access_deco/storage_texture.wgsl.expected.msl b/test/deprecated/access_deco/storage_texture.wgsl.expected.msl
new file mode 100644
index 0000000..44a2faf
--- /dev/null
+++ b/test/deprecated/access_deco/storage_texture.wgsl.expected.msl
@@ -0,0 +1,12 @@
+deprecated/access_deco/storage_texture.wgsl:1:84 warning: use of deprecated language feature: access control is expected as last parameter of storage textures
+[[group(0), binding(0)]] var tex : [[access(write)]] texture_storage_2d<rgba32float>;
+                                                                                   ^
+
+#include <metal_stdlib>
+
+using namespace metal;
+kernel void tint_symbol() {
+  int2 x = int2(tex.get_width(), tex.get_height());
+  return;
+}
+
diff --git a/test/deprecated/access_deco/storage_texture.wgsl.expected.spvasm b/test/deprecated/access_deco/storage_texture.wgsl.expected.spvasm
new file mode 100644
index 0000000..03c770e
--- /dev/null
+++ b/test/deprecated/access_deco/storage_texture.wgsl.expected.spvasm
@@ -0,0 +1,38 @@
+deprecated/access_deco/storage_texture.wgsl:1:84 warning: use of deprecated language feature: access control is expected as last parameter of storage textures
+[[group(0), binding(0)]] var tex : [[access(write)]] texture_storage_2d<rgba32float>;
+                                                                                   ^
+
+; SPIR-V
+; Version: 1.3
+; Generator: Google Tint Compiler; 0
+; Bound: 16
+; Schema: 0
+               OpCapability Shader
+               OpCapability ImageQuery
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint GLCompute %main "main"
+               OpExecutionMode %main LocalSize 1 1 1
+               OpName %tex "tex"
+               OpName %main "main"
+               OpName %x "x"
+               OpDecorate %tex NonReadable
+               OpDecorate %tex DescriptorSet 0
+               OpDecorate %tex Binding 0
+      %float = OpTypeFloat 32
+          %3 = OpTypeImage %float 2D 0 0 0 2 Rgba32f
+%_ptr_UniformConstant_3 = OpTypePointer UniformConstant %3
+        %tex = OpVariable %_ptr_UniformConstant_3 UniformConstant
+       %void = OpTypeVoid
+          %5 = OpTypeFunction %void
+        %int = OpTypeInt 32 1
+      %v2int = OpTypeVector %int 2
+%_ptr_Function_v2int = OpTypePointer Function %v2int
+         %15 = OpConstantNull %v2int
+       %main = OpFunction %void None %5
+          %8 = OpLabel
+          %x = OpVariable %_ptr_Function_v2int Function %15
+         %12 = OpLoad %3 %tex
+          %9 = OpImageQuerySize %v2int %12
+               OpStore %x %9
+               OpReturn
+               OpFunctionEnd
diff --git a/test/deprecated/access_deco/storage_texture.wgsl.expected.wgsl b/test/deprecated/access_deco/storage_texture.wgsl.expected.wgsl
new file mode 100644
index 0000000..b7a6aec
--- /dev/null
+++ b/test/deprecated/access_deco/storage_texture.wgsl.expected.wgsl
@@ -0,0 +1,10 @@
+deprecated/access_deco/storage_texture.wgsl:1:84 warning: use of deprecated language feature: access control is expected as last parameter of storage textures
+[[group(0), binding(0)]] var tex : [[access(write)]] texture_storage_2d<rgba32float>;
+                                                                                   ^
+
+[[group(0), binding(0)]] var tex : texture_storage_2d<rgba32float, write>;
+
+[[stage(compute)]]
+fn main() {
+  var x : vec2<i32> = textureDimensions(tex);
+}
diff --git a/test/intrinsics/arrayLength.wgsl b/test/intrinsics/arrayLength.wgsl
index 6ee6828..ef179fc 100644
--- a/test/intrinsics/arrayLength.wgsl
+++ b/test/intrinsics/arrayLength.wgsl
@@ -3,7 +3,7 @@
     a : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> G : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> G : S;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/intrinsics/arrayLength.wgsl.expected.wgsl b/test/intrinsics/arrayLength.wgsl.expected.wgsl
index 5f75515..bcbd967 100644
--- a/test/intrinsics/arrayLength.wgsl.expected.wgsl
+++ b/test/intrinsics/arrayLength.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   a : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> G : [[access(read)]] S;
+[[group(0), binding(0)]] var<storage, read> G : S;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/intrinsics/gen/arrayLength/647a40.wgsl b/test/intrinsics/gen/arrayLength/647a40.wgsl
index 3fa6e38..30519af 100644
--- a/test/intrinsics/gen/arrayLength/647a40.wgsl
+++ b/test/intrinsics/gen/arrayLength/647a40.wgsl
@@ -26,7 +26,7 @@
 struct SB {
   arg_0: array<u32>;
 };
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 fn arrayLength_647a40() {
   var res: u32 = arrayLength(sb.arg_0);
 }
diff --git a/test/intrinsics/gen/arrayLength/647a40.wgsl.expected.wgsl b/test/intrinsics/gen/arrayLength/647a40.wgsl.expected.wgsl
index 2719716..c6b65fa 100644
--- a/test/intrinsics/gen/arrayLength/647a40.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/arrayLength/647a40.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   arg_0 : array<u32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 fn arrayLength_647a40() {
   var res : u32 = arrayLength(sb.arg_0);
diff --git a/test/intrinsics/gen/arrayLength/721c9d.wgsl b/test/intrinsics/gen/arrayLength/721c9d.wgsl
index 1bf15a8..dca5bee 100644
--- a/test/intrinsics/gen/arrayLength/721c9d.wgsl
+++ b/test/intrinsics/gen/arrayLength/721c9d.wgsl
@@ -26,7 +26,7 @@
 struct SB {
   arg_0: array<i32>;
 };
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 fn arrayLength_721c9d() {
   var res: u32 = arrayLength(sb.arg_0);
 }
diff --git a/test/intrinsics/gen/arrayLength/721c9d.wgsl.expected.wgsl b/test/intrinsics/gen/arrayLength/721c9d.wgsl.expected.wgsl
index 963e865..3bf1a0b 100644
--- a/test/intrinsics/gen/arrayLength/721c9d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/arrayLength/721c9d.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   arg_0 : array<i32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 fn arrayLength_721c9d() {
   var res : u32 = arrayLength(sb.arg_0);
diff --git a/test/intrinsics/gen/arrayLength/b083be.wgsl b/test/intrinsics/gen/arrayLength/b083be.wgsl
index a48b181..40fc5e6 100644
--- a/test/intrinsics/gen/arrayLength/b083be.wgsl
+++ b/test/intrinsics/gen/arrayLength/b083be.wgsl
@@ -26,7 +26,7 @@
 struct SB {
   arg_0: array<f32>;
 };
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 fn arrayLength_b083be() {
   var res: u32 = arrayLength(sb.arg_0);
 }
diff --git a/test/intrinsics/gen/arrayLength/b083be.wgsl.expected.wgsl b/test/intrinsics/gen/arrayLength/b083be.wgsl.expected.wgsl
index 0701189..3b55b34 100644
--- a/test/intrinsics/gen/arrayLength/b083be.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/arrayLength/b083be.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   arg_0 : array<f32>;
 };
 
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 
 fn arrayLength_b083be() {
   var res : u32 = arrayLength(sb.arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/012b82.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/012b82.wgsl.expected.wgsl
index 8aa6f10..ac539f1 100644
--- a/test/intrinsics/gen/textureDimensions/012b82.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/012b82.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, write>;
 
 fn textureDimensions_012b82() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/08753d.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/08753d.wgsl.expected.wgsl
index 0c06897..11e00f3 100644
--- a/test/intrinsics/gen/textureDimensions/08753d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/08753d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16sint, write>;
 
 fn textureDimensions_08753d() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/08a62e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/08a62e.wgsl.expected.wgsl
index 6b9d4eb..cd7a984 100644
--- a/test/intrinsics/gen/textureDimensions/08a62e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/08a62e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32sint, read>;
 
 fn textureDimensions_08a62e() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0a5fcf.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0a5fcf.wgsl.expected.wgsl
index 8025f25..a59c9ab 100644
--- a/test/intrinsics/gen/textureDimensions/0a5fcf.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0a5fcf.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, read>;
 
 fn textureDimensions_0a5fcf() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0bab57.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0bab57.wgsl.expected.wgsl
index 2a1cdc2..07c3832 100644
--- a/test/intrinsics/gen/textureDimensions/0bab57.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0bab57.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16sint, read>;
 
 fn textureDimensions_0bab57() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0c4772.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0c4772.wgsl.expected.wgsl
index 1b29dc5..1116b91 100644
--- a/test/intrinsics/gen/textureDimensions/0c4772.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0c4772.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16float, write>;
 
 fn textureDimensions_0c4772() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0cce40.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0cce40.wgsl.expected.wgsl
index e1b4227..1f2e360 100644
--- a/test/intrinsics/gen/textureDimensions/0cce40.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0cce40.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32sint, write>;
 
 fn textureDimensions_0cce40() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0cf2ff.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0cf2ff.wgsl.expected.wgsl
index 0dcd6ab..eacaabe 100644
--- a/test/intrinsics/gen/textureDimensions/0cf2ff.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0cf2ff.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16uint, write>;
 
 fn textureDimensions_0cf2ff() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0d8b7e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0d8b7e.wgsl.expected.wgsl
index a756817..56bfe08 100644
--- a/test/intrinsics/gen/textureDimensions/0d8b7e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0d8b7e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, write>;
 
 fn textureDimensions_0d8b7e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/0e32ee.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/0e32ee.wgsl.expected.wgsl
index d22f78e..e61c4e2 100644
--- a/test/intrinsics/gen/textureDimensions/0e32ee.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/0e32ee.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16uint, write>;
 
 fn textureDimensions_0e32ee() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1147d6.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1147d6.wgsl.expected.wgsl
index 46318ce..5b3b8fc 100644
--- a/test/intrinsics/gen/textureDimensions/1147d6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1147d6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, read>;
 
 fn textureDimensions_1147d6() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/147998.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/147998.wgsl.expected.wgsl
index f519203..7b49a48 100644
--- a/test/intrinsics/gen/textureDimensions/147998.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/147998.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32float, write>;
 
 fn textureDimensions_147998() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/16036c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/16036c.wgsl.expected.wgsl
index 6b679ac..d9fba5c 100644
--- a/test/intrinsics/gen/textureDimensions/16036c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/16036c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, write>;
 
 fn textureDimensions_16036c() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/168fcc.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/168fcc.wgsl.expected.wgsl
index b66918a..9dcbc77 100644
--- a/test/intrinsics/gen/textureDimensions/168fcc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/168fcc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8unorm, read>;
 
 fn textureDimensions_168fcc() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/18bd57.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/18bd57.wgsl.expected.wgsl
index 6eb56a5..42ee0d4 100644
--- a/test/intrinsics/gen/textureDimensions/18bd57.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/18bd57.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, read>;
 
 fn textureDimensions_18bd57() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/19bffc.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/19bffc.wgsl.expected.wgsl
index b484dbe..1b97b63 100644
--- a/test/intrinsics/gen/textureDimensions/19bffc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/19bffc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32sint, read>;
 
 fn textureDimensions_19bffc() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1a58e7.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1a58e7.wgsl.expected.wgsl
index d8ec022..9df4e17 100644
--- a/test/intrinsics/gen/textureDimensions/1a58e7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1a58e7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, read>;
 
 fn textureDimensions_1a58e7() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1aa199.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1aa199.wgsl.expected.wgsl
index 07dcdb5..45e601f 100644
--- a/test/intrinsics/gen/textureDimensions/1aa199.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1aa199.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, read>;
 
 fn textureDimensions_1aa199() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1b71f0.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1b71f0.wgsl.expected.wgsl
index d2d1fde..80dec55 100644
--- a/test/intrinsics/gen/textureDimensions/1b71f0.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1b71f0.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16sint, write>;
 
 fn textureDimensions_1b71f0() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1d6c26.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1d6c26.wgsl.expected.wgsl
index 7ab9a37..552452e 100644
--- a/test/intrinsics/gen/textureDimensions/1d6c26.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1d6c26.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, write>;
 
 fn textureDimensions_1d6c26() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1e189c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1e189c.wgsl.expected.wgsl
index 4e8b5f6..65b30fc 100644
--- a/test/intrinsics/gen/textureDimensions/1e189c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1e189c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32sint, read>;
 
 fn textureDimensions_1e189c() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/1e9e39.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/1e9e39.wgsl.expected.wgsl
index 7cd094b..e2a609b 100644
--- a/test/intrinsics/gen/textureDimensions/1e9e39.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/1e9e39.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16float, write>;
 
 fn textureDimensions_1e9e39() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/214b7b.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/214b7b.wgsl.expected.wgsl
index b885786..95b156e 100644
--- a/test/intrinsics/gen/textureDimensions/214b7b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/214b7b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32float, read>;
 
 fn textureDimensions_214b7b() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/214dd4.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/214dd4.wgsl.expected.wgsl
index 760b456..1cab059 100644
--- a/test/intrinsics/gen/textureDimensions/214dd4.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/214dd4.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8sint, write>;
 
 fn textureDimensions_214dd4() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/26ef6c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/26ef6c.wgsl.expected.wgsl
index 83295f3..e1327eb 100644
--- a/test/intrinsics/gen/textureDimensions/26ef6c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/26ef6c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, write>;
 
 fn textureDimensions_26ef6c() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/2ad087.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/2ad087.wgsl.expected.wgsl
index c9e1f16..ed74a86 100644
--- a/test/intrinsics/gen/textureDimensions/2ad087.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/2ad087.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16sint, write>;
 
 fn textureDimensions_2ad087() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/2d32ae.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/2d32ae.wgsl.expected.wgsl
index 8ad08a8..40df1b3 100644
--- a/test/intrinsics/gen/textureDimensions/2d32ae.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/2d32ae.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32uint, read>;
 
 fn textureDimensions_2d32ae() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/2e0662.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/2e0662.wgsl.expected.wgsl
index 6ce2d76..0b5b5c1 100644
--- a/test/intrinsics/gen/textureDimensions/2e0662.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/2e0662.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8snorm, read>;
 
 fn textureDimensions_2e0662() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/2f289f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/2f289f.wgsl.expected.wgsl
index 64ae074..4a6cf0c 100644
--- a/test/intrinsics/gen/textureDimensions/2f289f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/2f289f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32sint, write>;
 
 fn textureDimensions_2f289f() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/318ecc.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/318ecc.wgsl.expected.wgsl
index 1c8d987..3c2f7aa 100644
--- a/test/intrinsics/gen/textureDimensions/318ecc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/318ecc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16uint, write>;
 
 fn textureDimensions_318ecc() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/340d06.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/340d06.wgsl.expected.wgsl
index b2d0826..6a907d4 100644
--- a/test/intrinsics/gen/textureDimensions/340d06.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/340d06.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32uint, write>;
 
 fn textureDimensions_340d06() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/398e30.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/398e30.wgsl.expected.wgsl
index 5d0bac4..66454ef 100644
--- a/test/intrinsics/gen/textureDimensions/398e30.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/398e30.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, write>;
 
 fn textureDimensions_398e30() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/39a600.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/39a600.wgsl.expected.wgsl
index ea6c5b2..c6dc285 100644
--- a/test/intrinsics/gen/textureDimensions/39a600.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/39a600.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, read>;
 
 fn textureDimensions_39a600() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/3a94ea.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/3a94ea.wgsl.expected.wgsl
index f369f54..22a6bbf 100644
--- a/test/intrinsics/gen/textureDimensions/3a94ea.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/3a94ea.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32uint, write>;
 
 fn textureDimensions_3a94ea() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/3aca08.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/3aca08.wgsl.expected.wgsl
index fbb8bf8..fe6cee3 100644
--- a/test/intrinsics/gen/textureDimensions/3aca08.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/3aca08.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32float, write>;
 
 fn textureDimensions_3aca08() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/3c5ad8.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/3c5ad8.wgsl.expected.wgsl
index 5f25817..78f31e9 100644
--- a/test/intrinsics/gen/textureDimensions/3c5ad8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/3c5ad8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8sint, write>;
 
 fn textureDimensions_3c5ad8() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/3d5817.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/3d5817.wgsl.expected.wgsl
index 981b928..a30d144 100644
--- a/test/intrinsics/gen/textureDimensions/3d5817.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/3d5817.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16uint, read>;
 
 fn textureDimensions_3d5817() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/40bc10.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/40bc10.wgsl.expected.wgsl
index 22ba5ee..8ddd8be 100644
--- a/test/intrinsics/gen/textureDimensions/40bc10.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/40bc10.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8uint, read>;
 
 fn textureDimensions_40bc10() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/4267ee.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/4267ee.wgsl.expected.wgsl
index f548fe4..f05b399 100644
--- a/test/intrinsics/gen/textureDimensions/4267ee.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/4267ee.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32float, write>;
 
 fn textureDimensions_4267ee() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/42d4e6.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/42d4e6.wgsl.expected.wgsl
index d218c7b..38c83b0 100644
--- a/test/intrinsics/gen/textureDimensions/42d4e6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/42d4e6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8unorm, write>;
 
 fn textureDimensions_42d4e6() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/441392.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/441392.wgsl.expected.wgsl
index 19693a9..723d588 100644
--- a/test/intrinsics/gen/textureDimensions/441392.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/441392.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32uint, read>;
 
 fn textureDimensions_441392() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/48cb89.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/48cb89.wgsl.expected.wgsl
index 5fc20b1..e41ddd8 100644
--- a/test/intrinsics/gen/textureDimensions/48cb89.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/48cb89.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16float, write>;
 
 fn textureDimensions_48cb89() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/48cbb2.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/48cbb2.wgsl.expected.wgsl
index c987541..906e9e2 100644
--- a/test/intrinsics/gen/textureDimensions/48cbb2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/48cbb2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, read>;
 
 fn textureDimensions_48cbb2() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/48f360.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/48f360.wgsl.expected.wgsl
index 25c40cd..6be9bc9 100644
--- a/test/intrinsics/gen/textureDimensions/48f360.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/48f360.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32sint, read>;
 
 fn textureDimensions_48f360() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/49d274.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/49d274.wgsl.expected.wgsl
index 2308b26..dd20941 100644
--- a/test/intrinsics/gen/textureDimensions/49d274.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/49d274.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, write>;
 
 fn textureDimensions_49d274() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/4df9a8.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/4df9a8.wgsl.expected.wgsl
index f29f9ac..ba16c04 100644
--- a/test/intrinsics/gen/textureDimensions/4df9a8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/4df9a8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32uint, write>;
 
 fn textureDimensions_4df9a8() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/55b23e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/55b23e.wgsl.expected.wgsl
index fecc1a3..ae54442 100644
--- a/test/intrinsics/gen/textureDimensions/55b23e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/55b23e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32float, write>;
 
 fn textureDimensions_55b23e() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/56ccfa.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/56ccfa.wgsl.expected.wgsl
index 4523c91..97dc807 100644
--- a/test/intrinsics/gen/textureDimensions/56ccfa.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/56ccfa.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16float, read>;
 
 fn textureDimensions_56ccfa() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/57da0b.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/57da0b.wgsl.expected.wgsl
index 485e888..aa29db6 100644
--- a/test/intrinsics/gen/textureDimensions/57da0b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/57da0b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32uint, write>;
 
 fn textureDimensions_57da0b() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/57e7b3.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/57e7b3.wgsl.expected.wgsl
index ef8e7a8..32ff0d9 100644
--- a/test/intrinsics/gen/textureDimensions/57e7b3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/57e7b3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8snorm, read>;
 
 fn textureDimensions_57e7b3() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/58a515.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/58a515.wgsl.expected.wgsl
index 238dcba..296fe97 100644
--- a/test/intrinsics/gen/textureDimensions/58a515.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/58a515.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, write>;
 
 fn textureDimensions_58a515() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/5985f3.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/5985f3.wgsl.expected.wgsl
index f8e2f8b..18d8afc 100644
--- a/test/intrinsics/gen/textureDimensions/5985f3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/5985f3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, write>;
 
 fn textureDimensions_5985f3() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/5caa5e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/5caa5e.wgsl.expected.wgsl
index 23e4b36..454b4fb 100644
--- a/test/intrinsics/gen/textureDimensions/5caa5e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/5caa5e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32uint, write>;
 
 fn textureDimensions_5caa5e() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/5e295d.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/5e295d.wgsl.expected.wgsl
index a5193f0..f55c312 100644
--- a/test/intrinsics/gen/textureDimensions/5e295d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/5e295d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, write>;
 
 fn textureDimensions_5e295d() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/60bf54.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/60bf54.wgsl.expected.wgsl
index 54326c9..2fc63f0 100644
--- a/test/intrinsics/gen/textureDimensions/60bf54.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/60bf54.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32sint, write>;
 
 fn textureDimensions_60bf54() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/63f3cf.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/63f3cf.wgsl.expected.wgsl
index c77564f..aa0a7f8 100644
--- a/test/intrinsics/gen/textureDimensions/63f3cf.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/63f3cf.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32float, write>;
 
 fn textureDimensions_63f3cf() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/66dc4e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/66dc4e.wgsl.expected.wgsl
index 8d5e3b5..e2e6ef4 100644
--- a/test/intrinsics/gen/textureDimensions/66dc4e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/66dc4e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, read>;
 
 fn textureDimensions_66dc4e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/670d90.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/670d90.wgsl.expected.wgsl
index 3f6a780..bb886d0 100644
--- a/test/intrinsics/gen/textureDimensions/670d90.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/670d90.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32float, read>;
 
 fn textureDimensions_670d90() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/68105c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/68105c.wgsl.expected.wgsl
index dba95a2..af6586e 100644
--- a/test/intrinsics/gen/textureDimensions/68105c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/68105c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32uint, write>;
 
 fn textureDimensions_68105c() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/6adac6.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/6adac6.wgsl.expected.wgsl
index 2cf5d09..c72dafc 100644
--- a/test/intrinsics/gen/textureDimensions/6adac6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/6adac6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32sint, write>;
 
 fn textureDimensions_6adac6() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/6c08ab.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/6c08ab.wgsl.expected.wgsl
index 739dd84..961b723 100644
--- a/test/intrinsics/gen/textureDimensions/6c08ab.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/6c08ab.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32float, read>;
 
 fn textureDimensions_6c08ab() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/6e2d12.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/6e2d12.wgsl.expected.wgsl
index 10b273b..ac32f1e 100644
--- a/test/intrinsics/gen/textureDimensions/6e2d12.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/6e2d12.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8sint, read>;
 
 fn textureDimensions_6e2d12() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/6f0d79.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/6f0d79.wgsl.expected.wgsl
index 624277c..84bc7ec 100644
--- a/test/intrinsics/gen/textureDimensions/6f0d79.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/6f0d79.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, write>;
 
 fn textureDimensions_6f0d79() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/702c53.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/702c53.wgsl.expected.wgsl
index c303a34..d8cd581 100644
--- a/test/intrinsics/gen/textureDimensions/702c53.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/702c53.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8unorm, write>;
 
 fn textureDimensions_702c53() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/70e26a.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/70e26a.wgsl.expected.wgsl
index 975437a..6114a9d 100644
--- a/test/intrinsics/gen/textureDimensions/70e26a.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/70e26a.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32uint, read>;
 
 fn textureDimensions_70e26a() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/71e8f7.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/71e8f7.wgsl.expected.wgsl
index 3380b0e..60146b8 100644
--- a/test/intrinsics/gen/textureDimensions/71e8f7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/71e8f7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32uint, read>;
 
 fn textureDimensions_71e8f7() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/770103.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/770103.wgsl.expected.wgsl
index b8ac441..d56bd69 100644
--- a/test/intrinsics/gen/textureDimensions/770103.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/770103.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32float, read>;
 
 fn textureDimensions_770103() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/7f5c2e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/7f5c2e.wgsl.expected.wgsl
index 6fedeb1..f2f9089 100644
--- a/test/intrinsics/gen/textureDimensions/7f5c2e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/7f5c2e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32sint, write>;
 
 fn textureDimensions_7f5c2e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8028f3.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8028f3.wgsl.expected.wgsl
index a8552be..c1d4f53 100644
--- a/test/intrinsics/gen/textureDimensions/8028f3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8028f3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32float, write>;
 
 fn textureDimensions_8028f3() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/811679.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/811679.wgsl.expected.wgsl
index 3912edc..7c2a044 100644
--- a/test/intrinsics/gen/textureDimensions/811679.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/811679.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32uint, write>;
 
 fn textureDimensions_811679() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/820596.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/820596.wgsl.expected.wgsl
index 3372df2..c0c9e05 100644
--- a/test/intrinsics/gen/textureDimensions/820596.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/820596.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32uint, write>;
 
 fn textureDimensions_820596() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/82138e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/82138e.wgsl.expected.wgsl
index 7b8a309..8c10113 100644
--- a/test/intrinsics/gen/textureDimensions/82138e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/82138e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16uint, read>;
 
 fn textureDimensions_82138e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8347ab.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8347ab.wgsl.expected.wgsl
index b87625c..f3b53fc 100644
--- a/test/intrinsics/gen/textureDimensions/8347ab.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8347ab.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8snorm, read>;
 
 fn textureDimensions_8347ab() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/83ee5a.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/83ee5a.wgsl.expected.wgsl
index ac6d124..5cbb82b 100644
--- a/test/intrinsics/gen/textureDimensions/83ee5a.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/83ee5a.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32sint, write>;
 
 fn textureDimensions_83ee5a() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8799ee.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8799ee.wgsl.expected.wgsl
index 82f35a8..3197f4e 100644
--- a/test/intrinsics/gen/textureDimensions/8799ee.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8799ee.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32sint, read>;
 
 fn textureDimensions_8799ee() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/89a864.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/89a864.wgsl.expected.wgsl
index b8e4b8c..e4d6d51 100644
--- a/test/intrinsics/gen/textureDimensions/89a864.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/89a864.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16float, read>;
 
 fn textureDimensions_89a864() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8b4fff.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8b4fff.wgsl.expected.wgsl
index 5869ada..200e8e3 100644
--- a/test/intrinsics/gen/textureDimensions/8b4fff.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8b4fff.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32sint, read>;
 
 fn textureDimensions_8b4fff() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8d89f8.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8d89f8.wgsl.expected.wgsl
index 4e4b06f..b4d874b 100644
--- a/test/intrinsics/gen/textureDimensions/8d89f8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8d89f8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32sint, read>;
 
 fn textureDimensions_8d89f8() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/8fca0f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/8fca0f.wgsl.expected.wgsl
index bb7611f..edbd3a4 100644
--- a/test/intrinsics/gen/textureDimensions/8fca0f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/8fca0f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32float, write>;
 
 fn textureDimensions_8fca0f() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/9042ab.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/9042ab.wgsl.expected.wgsl
index e508ed0..f448823 100644
--- a/test/intrinsics/gen/textureDimensions/9042ab.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/9042ab.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, write>;
 
 fn textureDimensions_9042ab() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/924742.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/924742.wgsl.expected.wgsl
index 0126b0e..c6d5ab7 100644
--- a/test/intrinsics/gen/textureDimensions/924742.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/924742.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32uint, read>;
 
 fn textureDimensions_924742() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/92ad20.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/92ad20.wgsl.expected.wgsl
index bb455ff..c7c1b7d 100644
--- a/test/intrinsics/gen/textureDimensions/92ad20.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/92ad20.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8uint, read>;
 
 fn textureDimensions_92ad20() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/9572e5.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/9572e5.wgsl.expected.wgsl
index 96d00a5..e5211ab 100644
--- a/test/intrinsics/gen/textureDimensions/9572e5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/9572e5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8unorm, read>;
 
 fn textureDimensions_9572e5() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/998f6b.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/998f6b.wgsl.expected.wgsl
index ab83144..af6f26c 100644
--- a/test/intrinsics/gen/textureDimensions/998f6b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/998f6b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, read>;
 
 fn textureDimensions_998f6b() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/9abfe5.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/9abfe5.wgsl.expected.wgsl
index eaf4cb7..76f4921 100644
--- a/test/intrinsics/gen/textureDimensions/9abfe5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/9abfe5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, write>;
 
 fn textureDimensions_9abfe5() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/9da9e2.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/9da9e2.wgsl.expected.wgsl
index a1c58b1..c120a98 100644
--- a/test/intrinsics/gen/textureDimensions/9da9e2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/9da9e2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8sint, write>;
 
 fn textureDimensions_9da9e2() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/9eb8d8.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/9eb8d8.wgsl.expected.wgsl
index 6e481c4..a97a20e 100644
--- a/test/intrinsics/gen/textureDimensions/9eb8d8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/9eb8d8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32uint, write>;
 
 fn textureDimensions_9eb8d8() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/a0aad1.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/a0aad1.wgsl.expected.wgsl
index 2ea0a43..ee2c2c1 100644
--- a/test/intrinsics/gen/textureDimensions/a0aad1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/a0aad1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32sint, read>;
 
 fn textureDimensions_a0aad1() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/a0e4ec.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/a0e4ec.wgsl.expected.wgsl
index 71446b5..eeaf9a6 100644
--- a/test/intrinsics/gen/textureDimensions/a0e4ec.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/a0e4ec.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8sint, read>;
 
 fn textureDimensions_a0e4ec() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/a863f2.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/a863f2.wgsl.expected.wgsl
index 28907fe..0bc4d60 100644
--- a/test/intrinsics/gen/textureDimensions/a863f2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/a863f2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32float, write>;
 
 fn textureDimensions_a863f2() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/ae457f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/ae457f.wgsl.expected.wgsl
index bc281cd..922d19d 100644
--- a/test/intrinsics/gen/textureDimensions/ae457f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/ae457f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, read>;
 
 fn textureDimensions_ae457f() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/b91240.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/b91240.wgsl.expected.wgsl
index 73263d7..6aebe9e 100644
--- a/test/intrinsics/gen/textureDimensions/b91240.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/b91240.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8snorm, write>;
 
 fn textureDimensions_b91240() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/ba6e15.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/ba6e15.wgsl.expected.wgsl
index ef3d759..e620f4a 100644
--- a/test/intrinsics/gen/textureDimensions/ba6e15.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/ba6e15.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32float, read>;
 
 fn textureDimensions_ba6e15() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/bb3dde.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/bb3dde.wgsl.expected.wgsl
index 364b3b2..4766a5f 100644
--- a/test/intrinsics/gen/textureDimensions/bb3dde.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/bb3dde.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32sint, write>;
 
 fn textureDimensions_bb3dde() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/c2215f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/c2215f.wgsl.expected.wgsl
index e2a2736..5d83932 100644
--- a/test/intrinsics/gen/textureDimensions/c2215f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/c2215f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, read>;
 
 fn textureDimensions_c2215f() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/c30e75.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/c30e75.wgsl.expected.wgsl
index aa76018..30ae071 100644
--- a/test/intrinsics/gen/textureDimensions/c30e75.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/c30e75.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32sint, write>;
 
 fn textureDimensions_c30e75() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/c60b66.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/c60b66.wgsl.expected.wgsl
index d023435..5d93e28 100644
--- a/test/intrinsics/gen/textureDimensions/c60b66.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/c60b66.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16sint, read>;
 
 fn textureDimensions_c60b66() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/c74533.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/c74533.wgsl.expected.wgsl
index 8acd040..bee736c 100644
--- a/test/intrinsics/gen/textureDimensions/c74533.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/c74533.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32uint, read>;
 
 fn textureDimensions_c74533() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/c7943d.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/c7943d.wgsl.expected.wgsl
index a78b4f4..a2ae851 100644
--- a/test/intrinsics/gen/textureDimensions/c7943d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/c7943d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8uint, write>;
 
 fn textureDimensions_c7943d() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/caaabb.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/caaabb.wgsl.expected.wgsl
index 1e79cdb..a201571 100644
--- a/test/intrinsics/gen/textureDimensions/caaabb.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/caaabb.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, read>;
 
 fn textureDimensions_caaabb() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cc5478.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cc5478.wgsl.expected.wgsl
index 94d868a..1245f54 100644
--- a/test/intrinsics/gen/textureDimensions/cc5478.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cc5478.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8unorm, read>;
 
 fn textureDimensions_cc5478() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cc968c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cc968c.wgsl.expected.wgsl
index 0535708..247fc37 100644
--- a/test/intrinsics/gen/textureDimensions/cc968c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cc968c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32sint, write>;
 
 fn textureDimensions_cc968c() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cccc8f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cccc8f.wgsl.expected.wgsl
index 84b8ce7..1a52363 100644
--- a/test/intrinsics/gen/textureDimensions/cccc8f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cccc8f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8snorm, write>;
 
 fn textureDimensions_cccc8f() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cd76a7.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cd76a7.wgsl.expected.wgsl
index 808c1ae..97e08ce 100644
--- a/test/intrinsics/gen/textureDimensions/cd76a7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cd76a7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8unorm, write>;
 
 fn textureDimensions_cd76a7() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cdaff9.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cdaff9.wgsl.expected.wgsl
index 2f6b64c..5857cc8 100644
--- a/test/intrinsics/gen/textureDimensions/cdaff9.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cdaff9.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32float, read>;
 
 fn textureDimensions_cdaff9() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cdf473.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cdf473.wgsl.expected.wgsl
index f25baa9..74e8404 100644
--- a/test/intrinsics/gen/textureDimensions/cdf473.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cdf473.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, write>;
 
 fn textureDimensions_cdf473() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cf1d42.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cf1d42.wgsl.expected.wgsl
index 4a3610d..94919bd 100644
--- a/test/intrinsics/gen/textureDimensions/cf1d42.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cf1d42.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16float, read>;
 
 fn textureDimensions_cf1d42() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/cf7e43.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/cf7e43.wgsl.expected.wgsl
index db7d588..ff42b8b 100644
--- a/test/intrinsics/gen/textureDimensions/cf7e43.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/cf7e43.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8snorm, write>;
 
 fn textureDimensions_cf7e43() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/d40b9e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/d40b9e.wgsl.expected.wgsl
index a3480ee..3de5d35 100644
--- a/test/intrinsics/gen/textureDimensions/d40b9e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/d40b9e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8sint, read>;
 
 fn textureDimensions_d40b9e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/d4106f.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/d4106f.wgsl.expected.wgsl
index 3dd7473..8a56652 100644
--- a/test/intrinsics/gen/textureDimensions/d4106f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/d4106f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16sint, read>;
 
 fn textureDimensions_d4106f() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/d8f951.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/d8f951.wgsl.expected.wgsl
index b807203..8664a89 100644
--- a/test/intrinsics/gen/textureDimensions/d8f951.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/d8f951.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32float, read>;
 
 fn textureDimensions_d8f951() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/da3099.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/da3099.wgsl.expected.wgsl
index 738261e..4c533e2 100644
--- a/test/intrinsics/gen/textureDimensions/da3099.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/da3099.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16uint, read>;
 
 fn textureDimensions_da3099() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/dba47c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/dba47c.wgsl.expected.wgsl
index e8ad8b5..01ff304 100644
--- a/test/intrinsics/gen/textureDimensions/dba47c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/dba47c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32uint, read>;
 
 fn textureDimensions_dba47c() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/dc2dd0.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/dc2dd0.wgsl.expected.wgsl
index cbfe2d9..93c08fb 100644
--- a/test/intrinsics/gen/textureDimensions/dc2dd0.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/dc2dd0.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8uint, write>;
 
 fn textureDimensions_dc2dd0() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e10157.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e10157.wgsl.expected.wgsl
index cea3ee5..8e8fa05 100644
--- a/test/intrinsics/gen/textureDimensions/e10157.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e10157.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8uint, read>;
 
 fn textureDimensions_e10157() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e93464.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e93464.wgsl.expected.wgsl
index 57ba706..dbda02c 100644
--- a/test/intrinsics/gen/textureDimensions/e93464.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e93464.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32sint, read>;
 
 fn textureDimensions_e93464() {
   var res : i32 = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e9628c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e9628c.wgsl.expected.wgsl
index f159ee1..820cdcc 100644
--- a/test/intrinsics/gen/textureDimensions/e9628c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e9628c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, read>;
 
 fn textureDimensions_e9628c() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e9e96c.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e9e96c.wgsl.expected.wgsl
index 80b69f6..2c05b97 100644
--- a/test/intrinsics/gen/textureDimensions/e9e96c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e9e96c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, write>;
 
 fn textureDimensions_e9e96c() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e9fe54.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e9fe54.wgsl.expected.wgsl
index c5a4c06..ded00bd 100644
--- a/test/intrinsics/gen/textureDimensions/e9fe54.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e9fe54.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32uint, read>;
 
 fn textureDimensions_e9fe54() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/e9fe58.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/e9fe58.wgsl.expected.wgsl
index f6d3e7e..7f30659 100644
--- a/test/intrinsics/gen/textureDimensions/e9fe58.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/e9fe58.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, read>;
 
 fn textureDimensions_e9fe58() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/f1b72b.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/f1b72b.wgsl.expected.wgsl
index 7b8c55c..64adcb1 100644
--- a/test/intrinsics/gen/textureDimensions/f1b72b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/f1b72b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32float, read>;
 
 fn textureDimensions_f1b72b() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/f7aa9e.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/f7aa9e.wgsl.expected.wgsl
index 2fa399f..1fe8272 100644
--- a/test/intrinsics/gen/textureDimensions/f7aa9e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/f7aa9e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, read>;
 
 fn textureDimensions_f7aa9e() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/f7e436.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/f7e436.wgsl.expected.wgsl
index 0b0ef26..10cbcbf 100644
--- a/test/intrinsics/gen/textureDimensions/f7e436.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/f7e436.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, read>;
 
 fn textureDimensions_f7e436() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/f931c7.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/f931c7.wgsl.expected.wgsl
index 0d82fc1..a3aad84 100644
--- a/test/intrinsics/gen/textureDimensions/f931c7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/f931c7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32float, write>;
 
 fn textureDimensions_f931c7() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/fa90e1.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/fa90e1.wgsl.expected.wgsl
index e7a2306..9dd338d 100644
--- a/test/intrinsics/gen/textureDimensions/fa90e1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/fa90e1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32float, read>;
 
 fn textureDimensions_fa90e1() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/fb5670.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/fb5670.wgsl.expected.wgsl
index 9e57cf6..901c479 100644
--- a/test/intrinsics/gen/textureDimensions/fb5670.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/fb5670.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, write>;
 
 fn textureDimensions_fb5670() {
   var res : vec2<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/fbbe4d.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/fbbe4d.wgsl.expected.wgsl
index 724fec4..18fc3b0 100644
--- a/test/intrinsics/gen/textureDimensions/fbbe4d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/fbbe4d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32uint, read>;
 
 fn textureDimensions_fbbe4d() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureDimensions/fcac78.wgsl.expected.wgsl b/test/intrinsics/gen/textureDimensions/fcac78.wgsl.expected.wgsl
index a5ca00a..fbbabf7 100644
--- a/test/intrinsics/gen/textureDimensions/fcac78.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureDimensions/fcac78.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8uint, write>;
 
 fn textureDimensions_fcac78() {
   var res : vec3<i32> = textureDimensions(arg_0);
diff --git a/test/intrinsics/gen/textureLoad/050c33.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/050c33.wgsl.expected.wgsl
index e02cdf0..53f59fb 100644
--- a/test/intrinsics/gen/textureLoad/050c33.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/050c33.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32uint, read>;
 
 fn textureLoad_050c33() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/072e26.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/072e26.wgsl.expected.wgsl
index be1af70..ecaffe9 100644
--- a/test/intrinsics/gen/textureLoad/072e26.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/072e26.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, read>;
 
 fn textureLoad_072e26() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/078bc4.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/078bc4.wgsl.expected.wgsl
index f2f0460..66edac1 100644
--- a/test/intrinsics/gen/textureLoad/078bc4.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/078bc4.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8snorm, read>;
 
 fn textureLoad_078bc4() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/127e12.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/127e12.wgsl.expected.wgsl
index aed5d39..6841826 100644
--- a/test/intrinsics/gen/textureLoad/127e12.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/127e12.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, read>;
 
 fn textureLoad_127e12() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/1561a7.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/1561a7.wgsl.expected.wgsl
index 4aa8b44..bd1d310 100644
--- a/test/intrinsics/gen/textureLoad/1561a7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/1561a7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32uint, read>;
 
 fn textureLoad_1561a7() {
   var res : vec4<u32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/1a062f.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/1a062f.wgsl.expected.wgsl
index 7c6460a..279eb74 100644
--- a/test/intrinsics/gen/textureLoad/1a062f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/1a062f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, read>;
 
 fn textureLoad_1a062f() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/1a8452.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/1a8452.wgsl.expected.wgsl
index 61bda65..625f24f 100644
--- a/test/intrinsics/gen/textureLoad/1a8452.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/1a8452.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8uint, read>;
 
 fn textureLoad_1a8452() {
   var res : vec4<u32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/20fa2f.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/20fa2f.wgsl.expected.wgsl
index 1f5f4cf..83e4525 100644
--- a/test/intrinsics/gen/textureLoad/20fa2f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/20fa2f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, read>;
 
 fn textureLoad_20fa2f() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/276a2c.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/276a2c.wgsl.expected.wgsl
index 03d832b..11ea867 100644
--- a/test/intrinsics/gen/textureLoad/276a2c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/276a2c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32uint, read>;
 
 fn textureLoad_276a2c() {
   var res : vec4<u32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/2887d7.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/2887d7.wgsl.expected.wgsl
index 1e7da98..ea3a147 100644
--- a/test/intrinsics/gen/textureLoad/2887d7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/2887d7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32float, read>;
 
 fn textureLoad_2887d7() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/2ae485.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/2ae485.wgsl.expected.wgsl
index 94ee8c4..f255805 100644
--- a/test/intrinsics/gen/textureLoad/2ae485.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/2ae485.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16sint, read>;
 
 fn textureLoad_2ae485() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/2d6cf7.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/2d6cf7.wgsl.expected.wgsl
index ead2ebf..42777c1 100644
--- a/test/intrinsics/gen/textureLoad/2d6cf7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/2d6cf7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32sint, read>;
 
 fn textureLoad_2d6cf7() {
   var res : vec4<i32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/3c0d9e.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/3c0d9e.wgsl.expected.wgsl
index 90a425b..09103fa 100644
--- a/test/intrinsics/gen/textureLoad/3c0d9e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/3c0d9e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8uint, read>;
 
 fn textureLoad_3c0d9e() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/3c9587.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/3c9587.wgsl.expected.wgsl
index c0e77d0..8bcb521 100644
--- a/test/intrinsics/gen/textureLoad/3c9587.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/3c9587.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8unorm, read>;
 
 fn textureLoad_3c9587() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/3d001b.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/3d001b.wgsl.expected.wgsl
index 47f2b47..173de56 100644
--- a/test/intrinsics/gen/textureLoad/3d001b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/3d001b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8sint, read>;
 
 fn textureLoad_3d001b() {
   var res : vec4<i32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/3d9c90.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/3d9c90.wgsl.expected.wgsl
index 5110820..e9ae4f8 100644
--- a/test/intrinsics/gen/textureLoad/3d9c90.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/3d9c90.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32float, read>;
 
 fn textureLoad_3d9c90() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/505aa2.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/505aa2.wgsl.expected.wgsl
index 4e4c985..39ceaad 100644
--- a/test/intrinsics/gen/textureLoad/505aa2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/505aa2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32sint, read>;
 
 fn textureLoad_505aa2() {
   var res : vec4<i32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/519ab5.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/519ab5.wgsl.expected.wgsl
index aa8b4a4..ae7d284 100644
--- a/test/intrinsics/gen/textureLoad/519ab5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/519ab5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8unorm, read>;
 
 fn textureLoad_519ab5() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/53378a.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/53378a.wgsl.expected.wgsl
index d064700..a8c1054 100644
--- a/test/intrinsics/gen/textureLoad/53378a.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/53378a.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32sint, read>;
 
 fn textureLoad_53378a() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/560573.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/560573.wgsl.expected.wgsl
index e464c72..23386cd 100644
--- a/test/intrinsics/gen/textureLoad/560573.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/560573.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, read>;
 
 fn textureLoad_560573() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/582015.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/582015.wgsl.expected.wgsl
index 07a18af..9a6f7d7 100644
--- a/test/intrinsics/gen/textureLoad/582015.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/582015.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, read>;
 
 fn textureLoad_582015() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/5bb7fb.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/5bb7fb.wgsl.expected.wgsl
index 28eb64c..21de3a6 100644
--- a/test/intrinsics/gen/textureLoad/5bb7fb.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/5bb7fb.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32uint, read>;
 
 fn textureLoad_5bb7fb() {
   var res : vec4<u32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/5d0a2f.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/5d0a2f.wgsl.expected.wgsl
index 281d549..17a102c 100644
--- a/test/intrinsics/gen/textureLoad/5d0a2f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/5d0a2f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, read>;
 
 fn textureLoad_5d0a2f() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/62d125.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/62d125.wgsl.expected.wgsl
index a0f70c0..3676aee 100644
--- a/test/intrinsics/gen/textureLoad/62d125.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/62d125.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8snorm, read>;
 
 fn textureLoad_62d125() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/6678b6.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/6678b6.wgsl.expected.wgsl
index 3eede21..17aa278 100644
--- a/test/intrinsics/gen/textureLoad/6678b6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/6678b6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16sint, read>;
 
 fn textureLoad_6678b6() {
   var res : vec4<i32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/67edca.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/67edca.wgsl.expected.wgsl
index aae3e6c..f1e9229 100644
--- a/test/intrinsics/gen/textureLoad/67edca.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/67edca.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32uint, read>;
 
 fn textureLoad_67edca() {
   var res : vec4<u32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/749704.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/749704.wgsl.expected.wgsl
index 40aa2c4..30ce4a8 100644
--- a/test/intrinsics/gen/textureLoad/749704.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/749704.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32uint, read>;
 
 fn textureLoad_749704() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/83cea4.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/83cea4.wgsl.expected.wgsl
index 747041d..baa2499 100644
--- a/test/intrinsics/gen/textureLoad/83cea4.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/83cea4.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16uint, read>;
 
 fn textureLoad_83cea4() {
   var res : vec4<u32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/8e5032.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/8e5032.wgsl.expected.wgsl
index eda9388..03b14af 100644
--- a/test/intrinsics/gen/textureLoad/8e5032.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/8e5032.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, read>;
 
 fn textureLoad_8e5032() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/936952.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/936952.wgsl.expected.wgsl
index 750c3ef..e697b1a 100644
--- a/test/intrinsics/gen/textureLoad/936952.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/936952.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, read>;
 
 fn textureLoad_936952() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/9a7c90.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/9a7c90.wgsl.expected.wgsl
index 355df01..9da0be5 100644
--- a/test/intrinsics/gen/textureLoad/9a7c90.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/9a7c90.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8uint, read>;
 
 fn textureLoad_9a7c90() {
   var res : vec4<u32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/9c2a14.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/9c2a14.wgsl.expected.wgsl
index 35f6a52..5aa4f8d 100644
--- a/test/intrinsics/gen/textureLoad/9c2a14.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/9c2a14.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32float, read>;
 
 fn textureLoad_9c2a14() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/a6a85a.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/a6a85a.wgsl.expected.wgsl
index 4ad2dcd..976dec1 100644
--- a/test/intrinsics/gen/textureLoad/a6a85a.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/a6a85a.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8unorm, read>;
 
 fn textureLoad_a6a85a() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/a6b61d.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/a6b61d.wgsl.expected.wgsl
index daf68a4..d4c44c8 100644
--- a/test/intrinsics/gen/textureLoad/a6b61d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/a6b61d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, read>;
 
 fn textureLoad_a6b61d() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/a7a3c3.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/a7a3c3.wgsl.expected.wgsl
index fdd3652..d6f6974 100644
--- a/test/intrinsics/gen/textureLoad/a7a3c3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/a7a3c3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16sint, read>;
 
 fn textureLoad_a7a3c3() {
   var res : vec4<i32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/b1bf79.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/b1bf79.wgsl.expected.wgsl
index 92d14f4..570f9ce 100644
--- a/test/intrinsics/gen/textureLoad/b1bf79.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/b1bf79.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32sint, read>;
 
 fn textureLoad_b1bf79() {
   var res : vec4<i32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/b58c6d.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/b58c6d.wgsl.expected.wgsl
index f6bc2f4..d3ea3c8 100644
--- a/test/intrinsics/gen/textureLoad/b58c6d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/b58c6d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, read>;
 
 fn textureLoad_b58c6d() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/b6c458.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/b6c458.wgsl.expected.wgsl
index 4bf8545..1f4817e 100644
--- a/test/intrinsics/gen/textureLoad/b6c458.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/b6c458.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32uint, read>;
 
 fn textureLoad_b6c458() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/bfd154.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/bfd154.wgsl.expected.wgsl
index 0acf1d8..b838f9e 100644
--- a/test/intrinsics/gen/textureLoad/bfd154.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/bfd154.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32uint, read>;
 
 fn textureLoad_bfd154() {
   var res : vec4<u32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/c02b74.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c02b74.wgsl.expected.wgsl
index 855caf6..bd1e6cc 100644
--- a/test/intrinsics/gen/textureLoad/c02b74.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c02b74.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16float, read>;
 
 fn textureLoad_c02b74() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/c07013.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c07013.wgsl.expected.wgsl
index 39db351..da23603 100644
--- a/test/intrinsics/gen/textureLoad/c07013.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c07013.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32float, read>;
 
 fn textureLoad_c07013() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/c40dcb.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c40dcb.wgsl.expected.wgsl
index 43965d8..c30538f 100644
--- a/test/intrinsics/gen/textureLoad/c40dcb.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c40dcb.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, read>;
 
 fn textureLoad_c40dcb() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/c456bc.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c456bc.wgsl.expected.wgsl
index a85b4e0..79f85f6 100644
--- a/test/intrinsics/gen/textureLoad/c456bc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c456bc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32float, read>;
 
 fn textureLoad_c456bc() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/c7cbed.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c7cbed.wgsl.expected.wgsl
index 4b77212..3af835b 100644
--- a/test/intrinsics/gen/textureLoad/c7cbed.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c7cbed.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32float, read>;
 
 fn textureLoad_c7cbed() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/c9cc40.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/c9cc40.wgsl.expected.wgsl
index 73ec9de..fbd6521 100644
--- a/test/intrinsics/gen/textureLoad/c9cc40.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/c9cc40.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8sint, read>;
 
 fn textureLoad_c9cc40() {
   var res : vec4<i32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/d5c48d.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/d5c48d.wgsl.expected.wgsl
index d795c88..1c5665f 100644
--- a/test/intrinsics/gen/textureLoad/d5c48d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/d5c48d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32float, read>;
 
 fn textureLoad_d5c48d() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/d81c57.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/d81c57.wgsl.expected.wgsl
index c014838..77b6b33 100644
--- a/test/intrinsics/gen/textureLoad/d81c57.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/d81c57.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32float, read>;
 
 fn textureLoad_d81c57() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/d8617f.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/d8617f.wgsl.expected.wgsl
index 892d025..b4f96da 100644
--- a/test/intrinsics/gen/textureLoad/d8617f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/d8617f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, read>;
 
 fn textureLoad_d8617f() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/dbd554.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/dbd554.wgsl.expected.wgsl
index 3cbc34f..37d79eb 100644
--- a/test/intrinsics/gen/textureLoad/dbd554.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/dbd554.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32sint, read>;
 
 fn textureLoad_dbd554() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/ddeed3.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/ddeed3.wgsl.expected.wgsl
index c5757d2..64e2e1f 100644
--- a/test/intrinsics/gen/textureLoad/ddeed3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/ddeed3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32sint, read>;
 
 fn textureLoad_ddeed3() {
   var res : vec4<i32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/dee8e7.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/dee8e7.wgsl.expected.wgsl
index c21dfb7..733a7a5 100644
--- a/test/intrinsics/gen/textureLoad/dee8e7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/dee8e7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8sint, read>;
 
 fn textureLoad_dee8e7() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/e65916.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/e65916.wgsl.expected.wgsl
index 33db37a..e2e525d 100644
--- a/test/intrinsics/gen/textureLoad/e65916.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/e65916.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32sint, read>;
 
 fn textureLoad_e65916() {
   var res : vec4<i32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/e893d7.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/e893d7.wgsl.expected.wgsl
index 48373a5..dd32ccc 100644
--- a/test/intrinsics/gen/textureLoad/e893d7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/e893d7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16float, read>;
 
 fn textureLoad_e893d7() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/eb573b.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/eb573b.wgsl.expected.wgsl
index 11af36e..b0d25ec 100644
--- a/test/intrinsics/gen/textureLoad/eb573b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/eb573b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32sint, read>;
 
 fn textureLoad_eb573b() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/ecc823.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/ecc823.wgsl.expected.wgsl
index 3e5e549..07de250 100644
--- a/test/intrinsics/gen/textureLoad/ecc823.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/ecc823.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16uint, read>;
 
 fn textureLoad_ecc823() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>());
diff --git a/test/intrinsics/gen/textureLoad/ef5405.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/ef5405.wgsl.expected.wgsl
index 68c90ba..44064dd 100644
--- a/test/intrinsics/gen/textureLoad/ef5405.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/ef5405.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32uint, read>;
 
 fn textureLoad_ef5405() {
   var res : vec4<u32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/f06b69.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/f06b69.wgsl.expected.wgsl
index c20a1cd..0feefab 100644
--- a/test/intrinsics/gen/textureLoad/f06b69.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/f06b69.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32sint, read>;
 
 fn textureLoad_f06b69() {
   var res : vec4<i32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/f379e2.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/f379e2.wgsl.expected.wgsl
index a554623..55d846f 100644
--- a/test/intrinsics/gen/textureLoad/f379e2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/f379e2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, read>;
 
 fn textureLoad_f379e2() {
   var res : vec4<f32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/f56e6f.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/f56e6f.wgsl.expected.wgsl
index 394ca11..8066af7 100644
--- a/test/intrinsics/gen/textureLoad/f56e6f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/f56e6f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16uint, read>;
 
 fn textureLoad_f56e6f() {
   var res : vec4<u32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/f74bd8.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/f74bd8.wgsl.expected.wgsl
index 5402217..ac62fc1 100644
--- a/test/intrinsics/gen/textureLoad/f74bd8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/f74bd8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32float, read>;
 
 fn textureLoad_f74bd8() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureLoad/fc6d36.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/fc6d36.wgsl.expected.wgsl
index 6ab0bc3..6b50dcf 100644
--- a/test/intrinsics/gen/textureLoad/fc6d36.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/fc6d36.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, read>;
 
 fn textureLoad_fc6d36() {
   var res : vec4<i32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/fdebd0.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/fdebd0.wgsl.expected.wgsl
index 1e9118c..a64885e 100644
--- a/test/intrinsics/gen/textureLoad/fdebd0.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/fdebd0.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, read>;
 
 fn textureLoad_fdebd0() {
   var res : vec4<u32> = textureLoad(arg_0, vec2<i32>(), 1);
diff --git a/test/intrinsics/gen/textureLoad/fe222a.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/fe222a.wgsl.expected.wgsl
index 5f27e75..11fdd1f 100644
--- a/test/intrinsics/gen/textureLoad/fe222a.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/fe222a.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_1d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8snorm, read>;
 
 fn textureLoad_fe222a() {
   var res : vec4<f32> = textureLoad(arg_0, 1);
diff --git a/test/intrinsics/gen/textureLoad/feab99.wgsl.expected.wgsl b/test/intrinsics/gen/textureLoad/feab99.wgsl.expected.wgsl
index cb8f4b6..25865d4 100644
--- a/test/intrinsics/gen/textureLoad/feab99.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureLoad/feab99.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_3d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16float, read>;
 
 fn textureLoad_feab99() {
   var res : vec4<f32> = textureLoad(arg_0, vec3<i32>());
diff --git a/test/intrinsics/gen/textureNumLayers/058cc3.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/058cc3.wgsl.expected.wgsl
index 1a2a38d..77783aa 100644
--- a/test/intrinsics/gen/textureNumLayers/058cc3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/058cc3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, write>;
 
 fn textureNumLayers_058cc3() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/09d05d.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/09d05d.wgsl.expected.wgsl
index 5235e46..05314d0 100644
--- a/test/intrinsics/gen/textureNumLayers/09d05d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/09d05d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, write>;
 
 fn textureNumLayers_09d05d() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/13b4ce.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/13b4ce.wgsl.expected.wgsl
index 783081f..393a7a0 100644
--- a/test/intrinsics/gen/textureNumLayers/13b4ce.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/13b4ce.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, write>;
 
 fn textureNumLayers_13b4ce() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/22e53b.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/22e53b.wgsl.expected.wgsl
index 4932ed6..676195e 100644
--- a/test/intrinsics/gen/textureNumLayers/22e53b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/22e53b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, write>;
 
 fn textureNumLayers_22e53b() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/2f6bb3.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/2f6bb3.wgsl.expected.wgsl
index 105f35f..c3ae3e2 100644
--- a/test/intrinsics/gen/textureNumLayers/2f6bb3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/2f6bb3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, read>;
 
 fn textureNumLayers_2f6bb3() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/315298.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/315298.wgsl.expected.wgsl
index 6cf6c73..61a7bb0 100644
--- a/test/intrinsics/gen/textureNumLayers/315298.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/315298.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, read>;
 
 fn textureNumLayers_315298() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/3615e3.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/3615e3.wgsl.expected.wgsl
index 42d36f2..8ab4d01 100644
--- a/test/intrinsics/gen/textureNumLayers/3615e3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/3615e3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, read>;
 
 fn textureNumLayers_3615e3() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/390fd5.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/390fd5.wgsl.expected.wgsl
index 1d83dcc..4e6b984 100644
--- a/test/intrinsics/gen/textureNumLayers/390fd5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/390fd5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, read>;
 
 fn textureNumLayers_390fd5() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/45155d.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/45155d.wgsl.expected.wgsl
index 756cf9f..89e8b48 100644
--- a/test/intrinsics/gen/textureNumLayers/45155d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/45155d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, read>;
 
 fn textureNumLayers_45155d() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/4bf67b.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/4bf67b.wgsl.expected.wgsl
index f3c2619..ad275db 100644
--- a/test/intrinsics/gen/textureNumLayers/4bf67b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/4bf67b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, read>;
 
 fn textureNumLayers_4bf67b() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/562013.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/562013.wgsl.expected.wgsl
index c2c48bd..f61c9a3 100644
--- a/test/intrinsics/gen/textureNumLayers/562013.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/562013.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, write>;
 
 fn textureNumLayers_562013() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/57092f.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/57092f.wgsl.expected.wgsl
index b7f2f18..58808a4 100644
--- a/test/intrinsics/gen/textureNumLayers/57092f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/57092f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, read>;
 
 fn textureNumLayers_57092f() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/68a65b.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/68a65b.wgsl.expected.wgsl
index 606e2b0..51ccf5c 100644
--- a/test/intrinsics/gen/textureNumLayers/68a65b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/68a65b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, write>;
 
 fn textureNumLayers_68a65b() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/7f1937.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/7f1937.wgsl.expected.wgsl
index 4378023..e80248e 100644
--- a/test/intrinsics/gen/textureNumLayers/7f1937.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/7f1937.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, write>;
 
 fn textureNumLayers_7f1937() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/938763.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/938763.wgsl.expected.wgsl
index b898ee9..acac86b 100644
--- a/test/intrinsics/gen/textureNumLayers/938763.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/938763.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, read>;
 
 fn textureNumLayers_938763() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/9700fb.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/9700fb.wgsl.expected.wgsl
index 09a5873..b384e59 100644
--- a/test/intrinsics/gen/textureNumLayers/9700fb.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/9700fb.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, write>;
 
 fn textureNumLayers_9700fb() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/a216d2.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/a216d2.wgsl.expected.wgsl
index 595c790..fa9fd0f 100644
--- a/test/intrinsics/gen/textureNumLayers/a216d2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/a216d2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, write>;
 
 fn textureNumLayers_a216d2() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/aa08a7.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/aa08a7.wgsl.expected.wgsl
index 37ada31..b0678df 100644
--- a/test/intrinsics/gen/textureNumLayers/aa08a7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/aa08a7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, read>;
 
 fn textureNumLayers_aa08a7() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/ab0c9b.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/ab0c9b.wgsl.expected.wgsl
index 86e0e6a..f8d69bd 100644
--- a/test/intrinsics/gen/textureNumLayers/ab0c9b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/ab0c9b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, read>;
 
 fn textureNumLayers_ab0c9b() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/b8cd76.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/b8cd76.wgsl.expected.wgsl
index e06a165..5bc1e44 100644
--- a/test/intrinsics/gen/textureNumLayers/b8cd76.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/b8cd76.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, read>;
 
 fn textureNumLayers_b8cd76() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/be1d70.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/be1d70.wgsl.expected.wgsl
index 6e4fd3a..a35ecdb 100644
--- a/test/intrinsics/gen/textureNumLayers/be1d70.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/be1d70.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, read>;
 
 fn textureNumLayers_be1d70() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/be3acb.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/be3acb.wgsl.expected.wgsl
index d986afd..3f561f7 100644
--- a/test/intrinsics/gen/textureNumLayers/be3acb.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/be3acb.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, read>;
 
 fn textureNumLayers_be3acb() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/c09917.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/c09917.wgsl.expected.wgsl
index d57c706..55b0623 100644
--- a/test/intrinsics/gen/textureNumLayers/c09917.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/c09917.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, read>;
 
 fn textureNumLayers_c09917() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/c7c7f2.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/c7c7f2.wgsl.expected.wgsl
index 781b878..70719ee 100644
--- a/test/intrinsics/gen/textureNumLayers/c7c7f2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/c7c7f2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, read>;
 
 fn textureNumLayers_c7c7f2() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/cd5dc8.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/cd5dc8.wgsl.expected.wgsl
index b90de11..2b9c43d 100644
--- a/test/intrinsics/gen/textureNumLayers/cd5dc8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/cd5dc8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, write>;
 
 fn textureNumLayers_cd5dc8() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/d5b228.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/d5b228.wgsl.expected.wgsl
index 5aab279..f27c252 100644
--- a/test/intrinsics/gen/textureNumLayers/d5b228.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/d5b228.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, write>;
 
 fn textureNumLayers_d5b228() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/e15642.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/e15642.wgsl.expected.wgsl
index 2545c66..5a38d3f 100644
--- a/test/intrinsics/gen/textureNumLayers/e15642.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/e15642.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(read)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, read>;
 
 fn textureNumLayers_e15642() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/e31be1.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/e31be1.wgsl.expected.wgsl
index bf169dd..54491f9 100644
--- a/test/intrinsics/gen/textureNumLayers/e31be1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/e31be1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, write>;
 
 fn textureNumLayers_e31be1() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/ee942f.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/ee942f.wgsl.expected.wgsl
index 2ba778e..77cfc30 100644
--- a/test/intrinsics/gen/textureNumLayers/ee942f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/ee942f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, write>;
 
 fn textureNumLayers_ee942f() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/f33005.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/f33005.wgsl.expected.wgsl
index 2141b9c..1630230 100644
--- a/test/intrinsics/gen/textureNumLayers/f33005.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/f33005.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, write>;
 
 fn textureNumLayers_f33005() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/fcec98.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/fcec98.wgsl.expected.wgsl
index d4c9e25..79cf26c 100644
--- a/test/intrinsics/gen/textureNumLayers/fcec98.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/fcec98.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, write>;
 
 fn textureNumLayers_fcec98() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureNumLayers/ff5e89.wgsl.expected.wgsl b/test/intrinsics/gen/textureNumLayers/ff5e89.wgsl.expected.wgsl
index a5ddef8..5498c71 100644
--- a/test/intrinsics/gen/textureNumLayers/ff5e89.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureNumLayers/ff5e89.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, write>;
 
 fn textureNumLayers_ff5e89() {
   var res : i32 = textureNumLayers(arg_0);
diff --git a/test/intrinsics/gen/textureStore/05ce15.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/05ce15.wgsl.expected.wgsl
index f31db20..b8dbde1 100644
--- a/test/intrinsics/gen/textureStore/05ce15.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/05ce15.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32float, write>;
 
 fn textureStore_05ce15() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/064c7f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/064c7f.wgsl.expected.wgsl
index 46247d5..7b0887c 100644
--- a/test/intrinsics/gen/textureStore/064c7f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/064c7f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32float, write>;
 
 fn textureStore_064c7f() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/068641.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/068641.wgsl.expected.wgsl
index dbb407b..5e28e98 100644
--- a/test/intrinsics/gen/textureStore/068641.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/068641.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16uint, write>;
 
 fn textureStore_068641() {
   textureStore(arg_0, vec3<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/0af6b5.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/0af6b5.wgsl.expected.wgsl
index 6a1e8dd..b51a2f2 100644
--- a/test/intrinsics/gen/textureStore/0af6b5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/0af6b5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32float, write>;
 
 fn textureStore_0af6b5() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/0c3dff.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/0c3dff.wgsl.expected.wgsl
index 96e508b..8abee33 100644
--- a/test/intrinsics/gen/textureStore/0c3dff.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/0c3dff.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16uint, write>;
 
 fn textureStore_0c3dff() {
   textureStore(arg_0, vec2<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/102722.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/102722.wgsl.expected.wgsl
index 78bc05d..6e9b31e 100644
--- a/test/intrinsics/gen/textureStore/102722.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/102722.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32uint, write>;
 
 fn textureStore_102722() {
   textureStore(arg_0, 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/1bbd08.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/1bbd08.wgsl.expected.wgsl
index d265bc0..ced6760 100644
--- a/test/intrinsics/gen/textureStore/1bbd08.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/1bbd08.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8unorm, write>;
 
 fn textureStore_1bbd08() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/1c02e7.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/1c02e7.wgsl.expected.wgsl
index 17368d2..4646962 100644
--- a/test/intrinsics/gen/textureStore/1c02e7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/1c02e7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32sint, write>;
 
 fn textureStore_1c02e7() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/22d955.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/22d955.wgsl.expected.wgsl
index cb9bde4..8536604 100644
--- a/test/intrinsics/gen/textureStore/22d955.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/22d955.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8uint, write>;
 
 fn textureStore_22d955() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/26bf70.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/26bf70.wgsl.expected.wgsl
index a2bb93d..ab7beef 100644
--- a/test/intrinsics/gen/textureStore/26bf70.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/26bf70.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32uint, write>;
 
 fn textureStore_26bf70() {
   textureStore(arg_0, vec2<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/2796b4.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/2796b4.wgsl.expected.wgsl
index f541a87..9ae12bf 100644
--- a/test/intrinsics/gen/textureStore/2796b4.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/2796b4.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32sint, write>;
 
 fn textureStore_2796b4() {
   textureStore(arg_0, vec3<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/2ac6c7.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/2ac6c7.wgsl.expected.wgsl
index 6dd1a80..ed127f0 100644
--- a/test/intrinsics/gen/textureStore/2ac6c7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/2ac6c7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32float, write>;
 
 fn textureStore_2ac6c7() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/2eb2a4.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/2eb2a4.wgsl.expected.wgsl
index c1d63b6..2038c93 100644
--- a/test/intrinsics/gen/textureStore/2eb2a4.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/2eb2a4.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16uint, write>;
 
 fn textureStore_2eb2a4() {
   textureStore(arg_0, 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/2ed2a3.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/2ed2a3.wgsl.expected.wgsl
index adb55f6..5d611eb 100644
--- a/test/intrinsics/gen/textureStore/2ed2a3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/2ed2a3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8snorm, write>;
 
 fn textureStore_2ed2a3() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/31745b.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/31745b.wgsl.expected.wgsl
index 0349879..d08889a 100644
--- a/test/intrinsics/gen/textureStore/31745b.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/31745b.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32sint, write>;
 
 fn textureStore_31745b() {
   textureStore(arg_0, vec2<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/32f368.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/32f368.wgsl.expected.wgsl
index c7addc8..3099b25 100644
--- a/test/intrinsics/gen/textureStore/32f368.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/32f368.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16float, write>;
 
 fn textureStore_32f368() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/331aee.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/331aee.wgsl.expected.wgsl
index 3d47b38..638ac34 100644
--- a/test/intrinsics/gen/textureStore/331aee.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/331aee.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32float, write>;
 
 fn textureStore_331aee() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/38e8d7.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/38e8d7.wgsl.expected.wgsl
index f87ee3e..a3528d8 100644
--- a/test/intrinsics/gen/textureStore/38e8d7.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/38e8d7.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32uint, write>;
 
 fn textureStore_38e8d7() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/3a52ac.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/3a52ac.wgsl.expected.wgsl
index 2eadd38..77717b8 100644
--- a/test/intrinsics/gen/textureStore/3a52ac.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/3a52ac.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16sint, write>;
 
 fn textureStore_3a52ac() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/3bb7a1.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/3bb7a1.wgsl.expected.wgsl
index 3171def..2380bdf 100644
--- a/test/intrinsics/gen/textureStore/3bb7a1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/3bb7a1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<r32float, write>;
 
 fn textureStore_3bb7a1() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/3bec15.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/3bec15.wgsl.expected.wgsl
index be5532b..e554d61 100644
--- a/test/intrinsics/gen/textureStore/3bec15.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/3bec15.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8uint, write>;
 
 fn textureStore_3bec15() {
   textureStore(arg_0, 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/441ba8.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/441ba8.wgsl.expected.wgsl
index 6b61a49..9dc38a0 100644
--- a/test/intrinsics/gen/textureStore/441ba8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/441ba8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32uint, write>;
 
 fn textureStore_441ba8() {
   textureStore(arg_0, vec3<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/4fc057.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/4fc057.wgsl.expected.wgsl
index 4c0fd68..8c8e1e8 100644
--- a/test/intrinsics/gen/textureStore/4fc057.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/4fc057.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8snorm, write>;
 
 fn textureStore_4fc057() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/5a2f8f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/5a2f8f.wgsl.expected.wgsl
index adeefea..bec35c5 100644
--- a/test/intrinsics/gen/textureStore/5a2f8f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/5a2f8f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16sint, write>;
 
 fn textureStore_5a2f8f() {
   textureStore(arg_0, 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/60975f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/60975f.wgsl.expected.wgsl
index 2391366..92f1984 100644
--- a/test/intrinsics/gen/textureStore/60975f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/60975f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8unorm, write>;
 
 fn textureStore_60975f() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/682fd6.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/682fd6.wgsl.expected.wgsl
index 7dcc695..335ab1c 100644
--- a/test/intrinsics/gen/textureStore/682fd6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/682fd6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rg32uint, write>;
 
 fn textureStore_682fd6() {
   textureStore(arg_0, vec2<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/6b75c3.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/6b75c3.wgsl.expected.wgsl
index 6ed15c6..83b679a 100644
--- a/test/intrinsics/gen/textureStore/6b75c3.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/6b75c3.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32float, write>;
 
 fn textureStore_6b75c3() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/6b80d2.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/6b80d2.wgsl.expected.wgsl
index 6e06e4f..1453f09 100644
--- a/test/intrinsics/gen/textureStore/6b80d2.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/6b80d2.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<r32sint, write>;
 
 fn textureStore_6b80d2() {
   textureStore(arg_0, 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/6cff2e.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/6cff2e.wgsl.expected.wgsl
index 900cfea..db87b5b 100644
--- a/test/intrinsics/gen/textureStore/6cff2e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/6cff2e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32uint, write>;
 
 fn textureStore_6cff2e() {
   textureStore(arg_0, vec2<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/6da692.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/6da692.wgsl.expected.wgsl
index eec8577..bf9b952 100644
--- a/test/intrinsics/gen/textureStore/6da692.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/6da692.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba16uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba16uint, write>;
 
 fn textureStore_6da692() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/731349.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/731349.wgsl.expected.wgsl
index 3dc131c..f9238c2 100644
--- a/test/intrinsics/gen/textureStore/731349.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/731349.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8unorm, write>;
 
 fn textureStore_731349() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/752da6.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/752da6.wgsl.expected.wgsl
index 8f5dfb6..dd1a7e3 100644
--- a/test/intrinsics/gen/textureStore/752da6.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/752da6.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba32sint, write>;
 
 fn textureStore_752da6() {
   textureStore(arg_0, vec2<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/77c0ae.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/77c0ae.wgsl.expected.wgsl
index 434cae5..d18f6bb 100644
--- a/test/intrinsics/gen/textureStore/77c0ae.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/77c0ae.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8uint, write>;
 
 fn textureStore_77c0ae() {
   textureStore(arg_0, vec2<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/7cec8d.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/7cec8d.wgsl.expected.wgsl
index 420fd1c..1afb946 100644
--- a/test/intrinsics/gen/textureStore/7cec8d.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/7cec8d.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32sint, write>;
 
 fn textureStore_7cec8d() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/7f7fae.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/7f7fae.wgsl.expected.wgsl
index d0bd9f3..5eb44e1 100644
--- a/test/intrinsics/gen/textureStore/7f7fae.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/7f7fae.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8unorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8unorm, write>;
 
 fn textureStore_7f7fae() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/804942.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/804942.wgsl.expected.wgsl
index 3306d47..a1a469e 100644
--- a/test/intrinsics/gen/textureStore/804942.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/804942.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<r32sint, write>;
 
 fn textureStore_804942() {
   textureStore(arg_0, vec2<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/805dae.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/805dae.wgsl.expected.wgsl
index 2e0e003..e927738 100644
--- a/test/intrinsics/gen/textureStore/805dae.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/805dae.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8snorm, write>;
 
 fn textureStore_805dae() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/83bcc1.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/83bcc1.wgsl.expected.wgsl
index 7659600..a5afd26 100644
--- a/test/intrinsics/gen/textureStore/83bcc1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/83bcc1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32uint, write>;
 
 fn textureStore_83bcc1() {
   textureStore(arg_0, 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/872747.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/872747.wgsl.expected.wgsl
index 084d473..e0a431f 100644
--- a/test/intrinsics/gen/textureStore/872747.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/872747.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32float, write>;
 
 fn textureStore_872747() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/8e0479.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/8e0479.wgsl.expected.wgsl
index f390e47..7af6f1d 100644
--- a/test/intrinsics/gen/textureStore/8e0479.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/8e0479.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32uint, write>;
 
 fn textureStore_8e0479() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/8f71a1.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/8f71a1.wgsl.expected.wgsl
index a6df58a..b6bb528 100644
--- a/test/intrinsics/gen/textureStore/8f71a1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/8f71a1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16sint, write>;
 
 fn textureStore_8f71a1() {
   textureStore(arg_0, vec3<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/969534.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/969534.wgsl.expected.wgsl
index bda2165..617bebe 100644
--- a/test/intrinsics/gen/textureStore/969534.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/969534.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32sint, write>;
 
 fn textureStore_969534() {
   textureStore(arg_0, 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/9a3ecc.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/9a3ecc.wgsl.expected.wgsl
index 1b3385b..e6b2ae3 100644
--- a/test/intrinsics/gen/textureStore/9a3ecc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/9a3ecc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba32sint, write>;
 
 fn textureStore_9a3ecc() {
   textureStore(arg_0, vec3<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/9d9cd5.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/9d9cd5.wgsl.expected.wgsl
index ca75315..29c626f 100644
--- a/test/intrinsics/gen/textureStore/9d9cd5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/9d9cd5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba32float, write>;
 
 fn textureStore_9d9cd5() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/9e3ec5.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/9e3ec5.wgsl.expected.wgsl
index 97220bf..8ae880d 100644
--- a/test/intrinsics/gen/textureStore/9e3ec5.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/9e3ec5.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16sint, write>;
 
 fn textureStore_9e3ec5() {
   textureStore(arg_0, vec2<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/ac67aa.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/ac67aa.wgsl.expected.wgsl
index f649c8b..18380d5 100644
--- a/test/intrinsics/gen/textureStore/ac67aa.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/ac67aa.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32uint, write>;
 
 fn textureStore_ac67aa() {
   textureStore(arg_0, vec3<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/b706b1.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/b706b1.wgsl.expected.wgsl
index d5a48e5..cbfd621 100644
--- a/test/intrinsics/gen/textureStore/b706b1.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/b706b1.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8sint, write>;
 
 fn textureStore_b706b1() {
   textureStore(arg_0, vec3<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/bbcb7f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/bbcb7f.wgsl.expected.wgsl
index 4c83b97..91d52f9 100644
--- a/test/intrinsics/gen/textureStore/bbcb7f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/bbcb7f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba8sint, write>;
 
 fn textureStore_bbcb7f() {
   textureStore(arg_0, vec2<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/be6e30.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/be6e30.wgsl.expected.wgsl
index cf60e0d..c2a01b1 100644
--- a/test/intrinsics/gen/textureStore/be6e30.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/be6e30.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d<rgba16float, write>;
 
 fn textureStore_be6e30() {
   textureStore(arg_0, vec2<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/bf775c.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/bf775c.wgsl.expected.wgsl
index 08ff4cb..be55c99 100644
--- a/test/intrinsics/gen/textureStore/bf775c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/bf775c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba8sint, write>;
 
 fn textureStore_bf775c() {
   textureStore(arg_0, 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/c5af1e.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/c5af1e.wgsl.expected.wgsl
index 671eef0..c7237ea 100644
--- a/test/intrinsics/gen/textureStore/c5af1e.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/c5af1e.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba16float, write>;
 
 fn textureStore_c5af1e() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/c863be.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/c863be.wgsl.expected.wgsl
index f5d4ab3..5b7c3fb 100644
--- a/test/intrinsics/gen/textureStore/c863be.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/c863be.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32float, write>;
 
 fn textureStore_c863be() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/d73b5c.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/d73b5c.wgsl.expected.wgsl
index 13b3190..c2373a0 100644
--- a/test/intrinsics/gen/textureStore/d73b5c.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/d73b5c.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rg32sint, write>;
 
 fn textureStore_d73b5c() {
   textureStore(arg_0, 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/dd7d81.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/dd7d81.wgsl.expected.wgsl
index 487e054..2e971b4 100644
--- a/test/intrinsics/gen/textureStore/dd7d81.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/dd7d81.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8snorm>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8snorm, write>;
 
 fn textureStore_dd7d81() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/dde364.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/dde364.wgsl.expected.wgsl
index ed94049..e07f74a 100644
--- a/test/intrinsics/gen/textureStore/dde364.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/dde364.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32uint, write>;
 
 fn textureStore_dde364() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/e885e8.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/e885e8.wgsl.expected.wgsl
index 53888d3..6e19428 100644
--- a/test/intrinsics/gen/textureStore/e885e8.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/e885e8.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba16float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba16float, write>;
 
 fn textureStore_e885e8() {
   textureStore(arg_0, 1, vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/eb702f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/eb702f.wgsl.expected.wgsl
index 5cf2b13..0e0e7e5 100644
--- a/test/intrinsics/gen/textureStore/eb702f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/eb702f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32float, write>;
 
 fn textureStore_eb702f() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/eb78b9.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/eb78b9.wgsl.expected.wgsl
index 31287b9..520ce22 100644
--- a/test/intrinsics/gen/textureStore/eb78b9.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/eb78b9.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32sint, write>;
 
 fn textureStore_eb78b9() {
   textureStore(arg_0, vec3<i32>(), vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/ee6acc.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/ee6acc.wgsl.expected.wgsl
index c68cc91..dd420db 100644
--- a/test/intrinsics/gen/textureStore/ee6acc.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/ee6acc.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rg32float>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rg32float, write>;
 
 fn textureStore_ee6acc() {
   textureStore(arg_0, vec3<i32>(), vec4<f32>());
diff --git a/test/intrinsics/gen/textureStore/ef9f2f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/ef9f2f.wgsl.expected.wgsl
index e8bf5e0..271825a 100644
--- a/test/intrinsics/gen/textureStore/ef9f2f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/ef9f2f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<r32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<r32uint, write>;
 
 fn textureStore_ef9f2f() {
   textureStore(arg_0, vec3<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/f8dead.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/f8dead.wgsl.expected.wgsl
index 8f23e0c..a23c85d 100644
--- a/test/intrinsics/gen/textureStore/f8dead.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/f8dead.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_3d<rgba8uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_3d<rgba8uint, write>;
 
 fn textureStore_f8dead() {
   textureStore(arg_0, vec3<i32>(), vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/f9be83.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/f9be83.wgsl.expected.wgsl
index efbe0fe..7986787 100644
--- a/test/intrinsics/gen/textureStore/f9be83.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/f9be83.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rg32sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rg32sint, write>;
 
 fn textureStore_f9be83() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<i32>());
diff --git a/test/intrinsics/gen/textureStore/fb9a8f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/fb9a8f.wgsl.expected.wgsl
index 78ac35d..c2488ec 100644
--- a/test/intrinsics/gen/textureStore/fb9a8f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/fb9a8f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_1d<rgba32uint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_1d<rgba32uint, write>;
 
 fn textureStore_fb9a8f() {
   textureStore(arg_0, 1, vec4<u32>());
diff --git a/test/intrinsics/gen/textureStore/fbf53f.wgsl.expected.wgsl b/test/intrinsics/gen/textureStore/fbf53f.wgsl.expected.wgsl
index 18f0471..fad0343 100644
--- a/test/intrinsics/gen/textureStore/fbf53f.wgsl.expected.wgsl
+++ b/test/intrinsics/gen/textureStore/fbf53f.wgsl.expected.wgsl
@@ -1,4 +1,4 @@
-[[group(1), binding(0)]] var arg_0 : [[access(write)]] texture_storage_2d_array<rgba8sint>;
+[[group(1), binding(0)]] var arg_0 : texture_storage_2d_array<rgba8sint, write>;
 
 fn textureStore_fbf53f() {
   textureStore(arg_0, vec2<i32>(), 1, vec4<i32>());
diff --git a/test/intrinsics/intrinsics.wgsl.tmpl b/test/intrinsics/intrinsics.wgsl.tmpl
index e0ca593..95d29b4 100644
--- a/test/intrinsics/intrinsics.wgsl.tmpl
+++ b/test/intrinsics/intrinsics.wgsl.tmpl
@@ -43,7 +43,7 @@
 {{-       end -}}
 {{-     end -}}
 };
-[[group(0), binding(0)]] var<storage> sb : [[access(read)]] SB;
+[[group(0), binding(0)]] var<storage, read> sb : SB;
 {{    end -}}
 
 {{- /* Generate module-scoped resource variables (textures, samplers, etc) */ -}}
diff --git a/test/ptr_ref/load/local/ptr_storage.wgsl b/test/ptr_ref/load/local/ptr_storage.wgsl
index d334f34..d8f764f 100644
--- a/test/ptr_ref/load/local/ptr_storage.wgsl
+++ b/test/ptr_ref/load/local/ptr_storage.wgsl
@@ -4,7 +4,7 @@
 };
 
 [[group(0), binding(0)]]
-var<storage> v : [[access(read_write)]] S;
+var<storage, read_write> v : S;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/ptr_ref/load/local/ptr_storage.wgsl.expected.wgsl b/test/ptr_ref/load/local/ptr_storage.wgsl.expected.wgsl
index 0c88535..c8c24d2 100644
--- a/test/ptr_ref/load/local/ptr_storage.wgsl.expected.wgsl
+++ b/test/ptr_ref/load/local/ptr_storage.wgsl.expected.wgsl
@@ -3,7 +3,7 @@
   a : i32;
 };
 
-[[group(0), binding(0)]] var<storage> v : [[access(read_write)]] S;
+[[group(0), binding(0)]] var<storage, read_write> v : S;
 
 [[stage(compute)]]
 fn main() {
diff --git a/test/samples/compute_boids.wgsl b/test/samples/compute_boids.wgsl
index 7570102..e0a1206 100644
--- a/test/samples/compute_boids.wgsl
+++ b/test/samples/compute_boids.wgsl
@@ -54,8 +54,8 @@
 };
 
 [[binding(0), group(0)]] var<uniform> params : SimParams;
-[[binding(1), group(0)]] var<storage> particlesA : [[access(read_write)]] Particles;
-[[binding(2), group(0)]] var<storage> particlesB : [[access(read_write)]] Particles;
+[[binding(1), group(0)]] var<storage, read_write> particlesA : Particles;
+[[binding(2), group(0)]] var<storage, read_write> particlesB : Particles;
 
 // https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
 [[stage(compute)]]
diff --git a/test/samples/compute_boids.wgsl.expected.wgsl b/test/samples/compute_boids.wgsl.expected.wgsl
index 882e263..f1b9ee4 100644
--- a/test/samples/compute_boids.wgsl.expected.wgsl
+++ b/test/samples/compute_boids.wgsl.expected.wgsl
@@ -33,9 +33,9 @@
 
 [[binding(0), group(0)]] var<uniform> params : SimParams;
 
-[[binding(1), group(0)]] var<storage> particlesA : [[access(read_write)]] Particles;
+[[binding(1), group(0)]] var<storage, read_write> particlesA : Particles;
 
-[[binding(2), group(0)]] var<storage> particlesB : [[access(read_write)]] Particles;
+[[binding(2), group(0)]] var<storage, read_write> particlesB : Particles;
 
 [[stage(compute)]]
 fn comp_main([[builtin(global_invocation_id)]] gl_GlobalInvocationID : vec3<u32>) {
diff --git a/test/shader_io/shared_struct_storage_buffer.wgsl b/test/shader_io/shared_struct_storage_buffer.wgsl
index 56f983c..5e2fabb 100644
--- a/test/shader_io/shared_struct_storage_buffer.wgsl
+++ b/test/shader_io/shared_struct_storage_buffer.wgsl
@@ -6,7 +6,7 @@
 };
 
 [[group(0), binding(0)]]
-var<storage> output : [[access(write)]] S;
+var<storage, write> output : S;
 
 [[stage(fragment)]]
 fn frag_main(input : S) {
diff --git a/test/shader_io/shared_struct_storage_buffer.wgsl.expected.wgsl b/test/shader_io/shared_struct_storage_buffer.wgsl.expected.wgsl
index db8682f..12065e6 100644
--- a/test/shader_io/shared_struct_storage_buffer.wgsl.expected.wgsl
+++ b/test/shader_io/shared_struct_storage_buffer.wgsl.expected.wgsl
@@ -8,7 +8,7 @@
   v : vec4<f32>;
 };
 
-[[group(0), binding(0)]] var<storage> output : [[access(write)]] S;
+[[group(0), binding(0)]] var<storage, write> output : S;
 
 [[stage(fragment)]]
 fn frag_main(input : S) {
diff --git a/tools/src/cmd/fix-tests/main.go b/tools/src/cmd/fix-tests/main.go
index 8865270..86cb459 100644
--- a/tools/src/cmd/fix-tests/main.go
+++ b/tools/src/cmd/fix-tests/main.go
@@ -77,7 +77,11 @@
 	testResultsPath := filepath.Join(tmpDir, "test-results.json")
 
 	// Run the tests
-	switch err := exec.Command(exe, "--gtest_output=json:"+testResultsPath).Run().(type) {
+	testArgs := []string{"--gtest_output=json:" + testResultsPath}
+	if len(args) > 1 {
+		testArgs = append(testArgs, args[1:]...)
+	}
+	switch err := exec.Command(exe, testArgs...).Run().(type) {
 	default:
 		return err
 	case nil: